Support for selective permissions

This commit is contained in:
Moxie Marlinspike
2017-11-24 22:00:30 -08:00
parent 99a26e2bcc
commit 64c8b4b2ef
71 changed files with 1309 additions and 317 deletions

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.components;
import android.Manifest;
import android.animation.Animator;
import android.annotation.TargetApi;
import android.app.Activity;
@@ -26,6 +27,7 @@ import android.widget.LinearLayout;
import android.widget.PopupWindow;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.ViewUtil;
public class AttachmentTypeSelector extends PopupWindow {
@@ -40,16 +42,19 @@ public class AttachmentTypeSelector extends PopupWindow {
private static final int ANIMATION_DURATION = 300;
@SuppressWarnings("unused")
private static final String TAG = AttachmentTypeSelector.class.getSimpleName();
private final @NonNull ImageView imageButton;
private final @NonNull ImageView audioButton;
private final @NonNull ImageView documentButton;
private final @NonNull ImageView contactButton;
private final @NonNull ImageView cameraButton;
private final @NonNull ImageView locationButton;
private final @NonNull ImageView gifButton;
private final @NonNull ImageView closeButton;
private final @NonNull LoaderManager loaderManager;
private final @NonNull RecentPhotoViewRail recentRail;
private final @NonNull ImageView imageButton;
private final @NonNull ImageView audioButton;
private final @NonNull ImageView documentButton;
private final @NonNull ImageView contactButton;
private final @NonNull ImageView cameraButton;
private final @NonNull ImageView locationButton;
private final @NonNull ImageView gifButton;
private final @NonNull ImageView closeButton;
private @Nullable View currentAnchor;
private @Nullable AttachmentClickedListener listener;
@@ -57,11 +62,12 @@ public class AttachmentTypeSelector extends PopupWindow {
public AttachmentTypeSelector(@NonNull Context context, @NonNull LoaderManager loaderManager, @Nullable AttachmentClickedListener listener) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.attachment_type_selector, null, true);
RecentPhotoViewRail recentPhotos = ViewUtil.findById(layout, R.id.recent_photos);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.attachment_type_selector, null, true);
this.listener = listener;
this.loaderManager = loaderManager;
this.recentRail = ViewUtil.findById(layout, R.id.recent_photos);
this.imageButton = ViewUtil.findById(layout, R.id.gallery_button);
this.audioButton = ViewUtil.findById(layout, R.id.audio_button);
this.documentButton = ViewUtil.findById(layout, R.id.document_button);
@@ -79,7 +85,7 @@ public class AttachmentTypeSelector extends PopupWindow {
this.locationButton.setOnClickListener(new PropagatingClickListener(ADD_LOCATION));
this.gifButton.setOnClickListener(new PropagatingClickListener(ADD_GIF));
this.closeButton.setOnClickListener(new CloseClickListener());
recentPhotos.setListener(new RecentPhotoSelectedListener());
this.recentRail.setListener(new RecentPhotoSelectedListener());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
ViewUtil.findById(layout, R.id.location_linear_layout).setVisibility(View.INVISIBLE);
@@ -94,10 +100,17 @@ public class AttachmentTypeSelector extends PopupWindow {
setFocusable(true);
setTouchable(true);
loaderManager.initLoader(1, null, recentPhotos);
loaderManager.initLoader(1, null, recentRail);
}
public void show(@NonNull Activity activity, final @NonNull View anchor) {
if (Permissions.hasAll(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
recentRail.setVisibility(View.VISIBLE);
loaderManager.restartLoader(1, null, recentRail);
} else {
recentRail.setVisibility(View.GONE);
}
this.currentAnchor = anchor;
showAtLocation(anchor, Gravity.BOTTOM, 0, 0);

View File

@@ -102,12 +102,7 @@ public class InputPanel extends LinearLayout
public void setListener(final @NonNull Listener listener) {
this.listener = listener;
emojiToggle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onEmojiToggle();
}
});
emojiToggle.setOnClickListener(v -> listener.onEmojiToggle());
}
public void setMediaListener(@NonNull MediaListener listener) {
@@ -118,6 +113,11 @@ public class InputPanel extends LinearLayout
emojiToggle.attach(emojiDrawer);
}
@Override
public void onRecordPermissionRequired() {
if (listener != null) listener.onRecorderPermissionRequired();
}
@Override
public void onRecordPressed(float startPositionX) {
if (listener != null) listener.onRecorderStarted();
@@ -211,10 +211,11 @@ public class InputPanel extends LinearLayout
}
public interface Listener {
public void onRecorderStarted();
public void onRecorderFinished();
public void onRecorderCanceled();
public void onEmojiToggle();
void onRecorderStarted();
void onRecorderFinished();
void onRecorderCanceled();
void onRecorderPermissionRequired();
void onEmojiToggle();
}
private static class SlideToCancel {

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.components;
import android.Manifest;
import android.content.Context;
import android.graphics.PorterDuff;
import android.support.annotation.Nullable;
@@ -18,6 +19,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.ViewUtil;
public class MicrophoneRecorderView extends FrameLayout implements View.OnTouchListener {
@@ -60,9 +62,13 @@ public class MicrophoneRecorderView extends FrameLayout implements View.OnTouchL
public boolean onTouch(View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
this.actionInProgress = true;
this.floatingRecordButton.display(event.getX());
if (listener != null) listener.onRecordPressed(event.getX());
if (!Permissions.hasAll(getContext(), Manifest.permission.RECORD_AUDIO)) {
if (listener != null) listener.onRecordPermissionRequired();
} else {
this.actionInProgress = true;
this.floatingRecordButton.display(event.getX());
if (listener != null) listener.onRecordPressed(event.getX());
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
@@ -88,10 +94,11 @@ public class MicrophoneRecorderView extends FrameLayout implements View.OnTouchL
}
public interface Listener {
public void onRecordPressed(float x);
public void onRecordReleased(float x);
public void onRecordCanceled(float x);
public void onRecordMoved(float x, float absoluteX);
void onRecordPressed(float x);
void onRecordReleased(float x);
void onRecordCanceled(float x);
void onRecordMoved(float x, float absoluteX);
void onRecordPermissionRequired();
}
private static class FloatingRecordButton {

View File

@@ -78,6 +78,7 @@ public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.Lo
private static class RecentPhotoAdapter extends CursorRecyclerViewAdapter<RecentPhotoAdapter.RecentPhotoViewHolder> {
@SuppressWarnings("unused")
private static final String TAG = RecentPhotoAdapter.class.getName();
@NonNull private final Uri baseUri;
@@ -117,11 +118,8 @@ public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.Lo
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(viewHolder.imageView);
viewHolder.imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (clickedListener != null) clickedListener.onItemClicked(uri);
}
viewHolder.imageView.setOnClickListener(v -> {
if (clickedListener != null) clickedListener.onItemClicked(uri);
});
}
@@ -143,6 +141,6 @@ public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.Lo
}
public interface OnItemClickedListener {
public void onItemClicked(Uri uri);
void onItemClicked(Uri uri);
}
}

View File

@@ -159,7 +159,11 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
fab.setTranslationY(difference);
if (percentageToThreshold == 1 && listener != null) listener.onAnswered();
if (percentageToThreshold == 1 && listener != null) {
fab.setVisibility(View.INVISIBLE);
lastY = event.getRawY();
listener.onAnswered();
}
} else {
differenceThreshold = ViewUtil.dpToPx(getContext(), DECLINE_THRESHOLD);
percentageToThreshold = Math.min(1, difference / differenceThreshold);
@@ -173,7 +177,11 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
fab.setRotation(135 * percentageToThreshold);
if (percentageToThreshold == 1 && listener != null) listener.onDeclined();
if (percentageToThreshold == 1 && listener != null) {
fab.setVisibility(View.INVISIBLE);
lastY = event.getRawY();
listener.onDeclined();
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {