asks for storage permission when saving media
This commit is contained in:
parent
2c984d5a2c
commit
29ffac03ef
|
@ -309,4 +309,6 @@ public interface SharedPreferenceConstants {
|
|||
String KEY_CACHE_SIZE_LIMIT = "cache_size_limit";
|
||||
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
|
||||
String KEY_BUG_REPORTS = "bug_reports";
|
||||
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
|
||||
String COMBINED_NOTIFICATIONS = "combined_notifications";
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.os.Bundle;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.squareup.otto.Bus;
|
||||
|
||||
|
@ -72,7 +73,7 @@ public class BaseAppCompatActivity extends ThemedAppCompatActivity implements Co
|
|||
private boolean mInstanceStateSaved;
|
||||
private boolean mIsVisible;
|
||||
private Rect mSystemWindowsInsets;
|
||||
private int mMetaState;
|
||||
private int mKeyMetaState;
|
||||
|
||||
@Override
|
||||
public boolean getSystemWindowsInsets(Rect insets) {
|
||||
|
@ -110,23 +111,31 @@ public class BaseAppCompatActivity extends ThemedAppCompatActivity implements Co
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
final int keyCode = event.getKeyCode();
|
||||
if (KeyEvent.isModifierKey(keyCode)) {
|
||||
mMetaState &= ~KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
|
||||
final int action = event.getAction();
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
mKeyMetaState |= KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
|
||||
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
||||
mKeyMetaState &= ~KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
|
||||
}
|
||||
}
|
||||
if (handleKeyboardShortcutSingle(mKeyboardShortcutsHandler, keyCode, event, mMetaState))
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (handleKeyboardShortcutSingle(mKeyboardShortcutsHandler, keyCode, event, mKeyMetaState))
|
||||
return true;
|
||||
return isKeyboardShortcutHandled(mKeyboardShortcutsHandler, keyCode, event, mMetaState) || super.onKeyUp(keyCode, event);
|
||||
return isKeyboardShortcutHandled(mKeyboardShortcutsHandler, keyCode, event, mKeyMetaState) || super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (KeyEvent.isModifierKey(keyCode)) {
|
||||
mMetaState |= KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
|
||||
}
|
||||
if (handleKeyboardShortcutRepeat(mKeyboardShortcutsHandler, keyCode, event.getRepeatCount(), event, mMetaState))
|
||||
if (handleKeyboardShortcutRepeat(mKeyboardShortcutsHandler, keyCode, event.getRepeatCount(), event, mKeyMetaState))
|
||||
return true;
|
||||
return isKeyboardShortcutHandled(mKeyboardShortcutsHandler, keyCode, event, mMetaState) || super.onKeyDown(keyCode, event);
|
||||
return isKeyboardShortcutHandled(mKeyboardShortcutsHandler, keyCode, event, mKeyMetaState) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,4 +255,8 @@ public class BaseAppCompatActivity extends ThemedAppCompatActivity implements Co
|
|||
mControlBarOffsetListeners.remove(listener);
|
||||
}
|
||||
|
||||
public int getKeyMetaState() {
|
||||
return mKeyMetaState;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.mariotaku.twidere.activity.support;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
|
@ -53,6 +54,7 @@ import android.widget.ImageButton;
|
|||
import android.widget.MediaController;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.davemorrissey.labs.subscaleview.ImageSource;
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
|
||||
|
@ -76,6 +78,7 @@ import org.mariotaku.twidere.model.ParcelableStatus;
|
|||
import org.mariotaku.twidere.util.AsyncTaskUtils;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.PermissionUtils;
|
||||
import org.mariotaku.twidere.util.SaveFileTask;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
@ -252,7 +255,7 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
|
|||
setTitle(String.format("%d / %d", mViewPager.getCurrentItem() + 1, mPagerAdapter.getCount()));
|
||||
}
|
||||
|
||||
public static class BaseImagePageFragment extends BaseSupportFragment
|
||||
public static class BaseImagePageFragment extends AbsMediaPageFragment
|
||||
implements DownloadListener, LoaderCallbacks<Result>, OnClickListener {
|
||||
|
||||
private SubsamplingScaleImageView mImageView;
|
||||
|
@ -385,7 +388,8 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
|
|||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void saveToGallery() {
|
||||
@Override
|
||||
protected void saveToGallery() {
|
||||
if (mSaveFileTask != null && mSaveFileTask.getStatus() == Status.RUNNING) return;
|
||||
final File file = mImageFile;
|
||||
final boolean hasImage = file != null && file.exists();
|
||||
|
@ -451,7 +455,7 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
|
|||
return true;
|
||||
}
|
||||
case R.id.save: {
|
||||
saveToGallery();
|
||||
requestAndSaveToGallery();
|
||||
return true;
|
||||
}
|
||||
case R.id.refresh: {
|
||||
|
@ -568,7 +572,40 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
|
|||
}
|
||||
}
|
||||
|
||||
public static final class VideoPageFragment extends BaseSupportFragment
|
||||
private static abstract class AbsMediaPageFragment extends BaseSupportFragment {
|
||||
protected void requestAndSaveToGallery() {
|
||||
if (PermissionUtils.hasPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
saveToGallery();
|
||||
} else {
|
||||
final String[] permissions;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
|
||||
} else {
|
||||
permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
}
|
||||
requestPermissions(permissions, REQUEST_REQUEST_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void saveToGallery();
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_REQUEST_PERMISSIONS: {
|
||||
if (PermissionUtils.hasPermission(permissions, grantResults, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
saveToGallery();
|
||||
} else {
|
||||
Toast.makeText(getContext(), R.string.save_media_no_storage_permission_message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class VideoPageFragment extends AbsMediaPageFragment
|
||||
implements VideoLoadingListener, OnPreparedListener, OnErrorListener, OnCompletionListener, OnClickListener {
|
||||
|
||||
private static final String[] SUPPORTED_VIDEO_TYPES;
|
||||
|
@ -783,7 +820,8 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
|
|||
return args.getParcelable(EXTRA_MEDIA);
|
||||
}
|
||||
|
||||
private void saveToGallery() {
|
||||
@Override
|
||||
protected void saveToGallery() {
|
||||
if (mSaveFileTask != null && mSaveFileTask.getStatus() == Status.RUNNING) return;
|
||||
final File file = mVideoFile;
|
||||
final Pair<String, String> urlAndType = mVideoUrlAndType;
|
||||
|
@ -914,7 +952,7 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
|
|||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.save: {
|
||||
saveToGallery();
|
||||
requestAndSaveToGallery();
|
||||
return true;
|
||||
}
|
||||
case R.id.refresh: {
|
||||
|
|
|
@ -120,7 +120,6 @@ import java.util.Locale;
|
|||
import me.uucky.colorpicker.internal.EffectViewHelper;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.buildDirectMessageConversationUri;
|
||||
import static org.mariotaku.twidere.util.Utils.showOkMessage;
|
||||
|
||||
public class MessagesConversationFragment extends BaseSupportFragment implements
|
||||
LoaderCallbacks<Cursor>, OnClickListener, OnItemSelectedListener, MenuButtonClickListener,
|
||||
|
@ -503,7 +502,7 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
}
|
||||
case R.id.copy: {
|
||||
if (ClipboardUtils.setText(getActivity(), mSelectedDirectMessage.text_plain)) {
|
||||
showOkMessage(getActivity(), R.string.text_copied, false);
|
||||
Utils.showOkMessage(getActivity(), R.string.text_copied, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -653,11 +652,16 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
|
|||
final EditTextEnterHandler queryEnterHandler = EditTextEnterHandler.attach(mEditUserQuery, new EnterListener() {
|
||||
@Override
|
||||
public boolean shouldCallListener() {
|
||||
return true;
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (!(activity instanceof BaseAppCompatActivity)) return false;
|
||||
return ((BaseAppCompatActivity) activity).getKeyMetaState() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHitEnter() {
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (!(activity instanceof BaseAppCompatActivity)) return false;
|
||||
if (((BaseAppCompatActivity) activity).getKeyMetaState() != 0) return false;
|
||||
final ParcelableCredentials account = (ParcelableCredentials) mAccountSpinner.getSelectedItem();
|
||||
if (account == null) return false;
|
||||
mEditText.setAccountId(account.account_id);
|
||||
|
|
|
@ -30,6 +30,7 @@ import android.util.Log;
|
|||
import org.mariotaku.twidere.BuildConfig;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.dagger.ApplicationModule;
|
||||
import org.mariotaku.twidere.util.net.NetworkUsageUtils;
|
||||
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
|
@ -49,6 +50,7 @@ public class ConnectivityStateReceiver extends BroadcastReceiver implements Cons
|
|||
Log.d(RECEIVER_LOGTAG, String.format("Received Broadcast %s", intent));
|
||||
}
|
||||
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) return;
|
||||
ApplicationModule.get(context).reloadConnectivitySettings();
|
||||
startRefreshServiceIfNeeded(context);
|
||||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
/**
|
||||
|
@ -30,4 +34,12 @@ public class PermissionUtils {
|
|||
if (idx != -1) return grantResults[idx];
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean hasPermission(Context context, String permission) {
|
||||
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
public static boolean hasPermission(String[] permissions, int[] grantResults, String permission) {
|
||||
return getPermission(permissions, grantResults, permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ public class TwitterAPIFactory implements TwidereConstants {
|
|||
if (enableProxy) {
|
||||
client.setProxy(getProxy(prefs));
|
||||
} else {
|
||||
client.setProxy(Proxy.NO_PROXY);
|
||||
client.setProxy(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -787,4 +787,8 @@
|
|||
<string name="invalid_consumer_secret">Invalid consumer secret</string>
|
||||
<string name="page_up">Page up</string>
|
||||
<string name="page_down">Page down</string>
|
||||
<string name="combined_notifications">Combined notifications</string>
|
||||
<string name="combined_notifications_summary_on">Notifications will be grouped</string>
|
||||
<string name="combined_notifications_summary_off">Notifications will be displayed separately</string>
|
||||
<string name="save_media_no_storage_permission_message">Storage permission is needed to save media.</string>
|
||||
</resources>
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/notifications">
|
||||
|
||||
|
@ -8,7 +7,7 @@
|
|||
android:key="cat_accounts"
|
||||
android:title="@string/accounts"
|
||||
app:switchDefault="true"
|
||||
app:switchKey="notification"/>
|
||||
app:switchKey="notification" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="cat_general"
|
||||
|
@ -16,13 +15,20 @@
|
|||
<org.mariotaku.twidere.preference.SilentNotificationsPreference
|
||||
android:key="silent_notifications"
|
||||
android:summary="@string/silent_notifications_summary"
|
||||
android:title="@string/silent_notifications"/>
|
||||
android:title="@string/silent_notifications" />
|
||||
|
||||
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="combined_notifications"
|
||||
android:summaryOff="@string/combined_notifications_summary_off"
|
||||
android:summaryOn="@string/combined_notifications_summary_on"
|
||||
android:title="@string/combined_notifications" />
|
||||
|
||||
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="pebble_notifications"
|
||||
android:summary="@string/pebble_notifications_summary"
|
||||
android:title="@string/pebble_notifications"/>
|
||||
android:title="@string/pebble_notifications" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Reference in New Issue