Copied from the support library v27.1.1.
* Created by Zhenjie Yan on 2018/4/28. */ public class FileProvider extends ContentProvider { private static final String[] COLUMNS = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}; private static final String META_DATA_FILE_PROVIDER_PATHS = "android.support.FILE_PROVIDER_PATHS"; private static final String TAG_ROOT_PATH = "root-path"; private static final String TAG_FILES_PATH = "files-path"; private static final String TAG_CACHE_PATH = "cache-path"; private static final String TAG_EXTERNAL = "external-path"; private static final String TAG_EXTERNAL_FILES = "external-files-path"; private static final String TAG_EXTERNAL_CACHE = "external-cache-path"; private static final String TAG_EXTERNAL_MEDIA = "external-media-path"; private static final String ATTR_NAME = "name"; private static final String ATTR_PATH = "path"; private static final File DEVICE_ROOT = new File("/"); private static final HashMapRequest executor.
* Created by Zhenjie Yan on 2016/9/10. */ public interface RequestExecutor { /** * Go request permission. */ void execute(); /** * Cancel the operation. */ void cancel(); } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/bridge/BridgeActivity.java ================================================ /* * Copyright © Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.bridge; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.view.KeyEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.yanzhenjie.permission.overlay.setting.LSettingPage; import com.yanzhenjie.permission.overlay.setting.MSettingPage; import com.yanzhenjie.permission.source.ActivitySource; import com.yanzhenjie.permission.source.Source; /** ** Request permission. *
* Created by Zhenjie Yan on 2017/4/27. */ public final class BridgeActivity extends Activity { private static final String KEY_TYPE = "KEY_TYPE"; private static final String KEY_PERMISSIONS = "KEY_PERMISSIONS"; private static final String KEY_ACTION_SUFFIX = "KEY_ACTION_SUFFIX"; /** * Request for permissions. */ static void requestAppDetails(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_APP_DETAILS); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for permissions. */ static void requestPermission(Source source, String suffix, String[] permissions) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_PERMISSION); intent.putExtra(KEY_PERMISSIONS, permissions); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for package install. */ static void requestInstall(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_INSTALL); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for overlay. */ static void requestOverlay(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_OVERLAY); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for alert window. */ static void requestAlertWindow(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_ALERT_WINDOW); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for notify. */ static void requestNotify(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_NOTIFY); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for notification listener. */ static void requestNotificationListener(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_NOTIFY_LISTENER); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } /** * Request for write system setting. */ static void requestWriteSetting(Source source, String suffix) { Intent intent = new Intent(source.getContext(), BridgeActivity.class); intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_WRITE_SETTING); intent.putExtra(KEY_ACTION_SUFFIX, suffix); source.startActivity(intent); } private String mActionSuffix; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) return; Intent intent = getIntent(); int operation = intent.getIntExtra(KEY_TYPE, -1); mActionSuffix = intent.getStringExtra(KEY_ACTION_SUFFIX); switch (operation) { case BridgeRequest.TYPE_APP_DETAILS: { Intent appDetailsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); appDetailsIntent.setData(Uri.fromParts("package", getPackageName(), null)); startActivityForResult(appDetailsIntent, BridgeRequest.TYPE_APP_DETAILS); break; } case BridgeRequest.TYPE_PERMISSION: { String[] permissions = intent.getStringArrayExtra(KEY_PERMISSIONS); requestPermissions(permissions, BridgeRequest.TYPE_PERMISSION); break; } case BridgeRequest.TYPE_INSTALL: { Intent manageIntent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); manageIntent.setData(Uri.fromParts("package", getPackageName(), null)); startActivityForResult(manageIntent, BridgeRequest.TYPE_INSTALL); break; } case BridgeRequest.TYPE_OVERLAY: { MSettingPage settingPage = new MSettingPage(new ActivitySource(this)); settingPage.start(BridgeRequest.TYPE_OVERLAY); break; } case BridgeRequest.TYPE_ALERT_WINDOW: { LSettingPage settingPage = new LSettingPage(new ActivitySource(this)); settingPage.start(BridgeRequest.TYPE_ALERT_WINDOW); break; } case BridgeRequest.TYPE_NOTIFY: { Intent settingIntent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS); settingIntent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); settingIntent.setData(Uri.fromParts("package", getPackageName(), null)); startActivityForResult(settingIntent, BridgeRequest.TYPE_NOTIFY); break; } case BridgeRequest.TYPE_NOTIFY_LISTENER: { Intent settingIntent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); settingIntent.setData(Uri.fromParts("package", getPackageName(), null)); startActivityForResult(settingIntent, BridgeRequest.TYPE_NOTIFY_LISTENER); break; } case BridgeRequest.TYPE_WRITE_SETTING: { Intent settingIntent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); settingIntent.setData(Uri.fromParts("package", getPackageName(), null)); startActivityForResult(settingIntent, BridgeRequest.TYPE_WRITE_SETTING); break; } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { Messenger.send(this, mActionSuffix); finish(); } @Override public void startActivityForResult(Intent intent, int requestCode) { super.startActivityForResult(intent, requestCode); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); Messenger.send(this, mActionSuffix); finish(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; } return super.onKeyDown(keyCode, event); } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/bridge/BridgeRequest.java ================================================ /* * Copyright 2019 Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.bridge; import com.yanzhenjie.permission.source.Source; import java.util.List; /** * Created by Zhenjie Yan on 2/13/19. */ public final class BridgeRequest { public static final int TYPE_APP_DETAILS = 1; public static final int TYPE_PERMISSION = 2; public static final int TYPE_INSTALL = 3; public static final int TYPE_OVERLAY = 4; public static final int TYPE_ALERT_WINDOW = 5; public static final int TYPE_NOTIFY = 6; public static final int TYPE_NOTIFY_LISTENER = 7; public static final int TYPE_WRITE_SETTING = 8; private final Source mSource; private int mType; private Callback mCallback; private ListPermissions.
* Created by Zhenjie Yan on 2017/8/4. */ public class Permission { public static final String READ_CALENDAR = "android.permission.READ_CALENDAR"; public static final String WRITE_CALENDAR = "android.permission.WRITE_CALENDAR"; public static final String CAMERA = "android.permission.CAMERA"; public static final String READ_CONTACTS = "android.permission.READ_CONTACTS"; public static final String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS"; public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"; public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION"; public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION"; public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; public static final String CALL_PHONE = "android.permission.CALL_PHONE"; public static final String USE_SIP = "android.permission.USE_SIP"; public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS"; public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS"; public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL"; public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG"; public static final String WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG"; public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS"; public static final String BODY_SENSORS = "android.permission.BODY_SENSORS"; public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION"; public static final String SEND_SMS = "android.permission.SEND_SMS"; public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS"; public static final String READ_SMS = "android.permission.READ_SMS"; public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"; public static final String RECEIVE_MMS = "android.permission.RECEIVE_MMS"; public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE"; public static final String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; public static final class Group { public static final String[] CALENDAR = new String[]{Permission.READ_CALENDAR, Permission.WRITE_CALENDAR}; public static final String[] CAMERA = new String[]{Permission.CAMERA}; public static final String[] CONTACTS = new String[]{Permission.READ_CONTACTS, Permission.WRITE_CONTACTS, Permission.GET_ACCOUNTS}; public static final String[] LOCATION = new String[]{Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_BACKGROUND_LOCATION}; public static final String[] MICROPHONE = new String[]{Permission.RECORD_AUDIO}; public static final String[] PHONE = new String[]{Permission.READ_PHONE_STATE, Permission.CALL_PHONE, Permission.USE_SIP, Permission.READ_PHONE_NUMBERS, Permission.ANSWER_PHONE_CALLS, Permission.ADD_VOICEMAIL}; public static final String[] CALL_LOG = new String[]{Permission.READ_CALL_LOG, Permission.WRITE_CALL_LOG, Permission.PROCESS_OUTGOING_CALLS}; public static final String[] SENSORS = new String[]{Permission.BODY_SENSORS}; public static final String[] ACTIVITY_RECOGNITION = new String[]{Permission.ACTIVITY_RECOGNITION}; public static final String[] SMS = new String[]{Permission.SEND_SMS, Permission.RECEIVE_SMS, Permission.READ_SMS, Permission.RECEIVE_WAP_PUSH, Permission.RECEIVE_MMS}; public static final String[] STORAGE = new String[]{Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE}; } /** * Turn permissions into text. */ public static ListPermission request.
* Created by Zhenjie Yan on 2016/9/9. */ public interface PermissionRequest { /** * One or more permissions. */ PermissionRequest permission(@NonNull @PermissionDef String... permissions); /** * One or more permissions group. * * @param groups use constants in {@link Permission.Group}. */ PermissionRequest permission(@NonNull String[]... groups); /** * Set request rationale. */ PermissionRequest rationale(@NonNull RationaleSettingRequest executor.
* Created by Zhenjie Yan on 2016/12/28. */ public class AllRequest implements SettingRequest { private Source mSource; public AllRequest(Source source) { this.mSource = source; } @Override public void start(int requestCode) { SettingPage setting = new SettingPage(mSource); setting.start(requestCode); } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/runtime/setting/SettingPage.java ================================================ /* * Copyright 2018 Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.runtime.setting; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; import com.yanzhenjie.permission.source.Source; /** * Created by Zhenjie Yan on 2018/4/30. */ public class SettingPage { private static final String MARK = Build.MANUFACTURER.toLowerCase(); private Source mSource; public SettingPage(Source source) { this.mSource = source; } /** * Start. * * @param requestCode this code will be returned in onActivityResult() when the activity exits. */ public void start(int requestCode) { Intent intent; if (MARK.contains("huawei")) { intent = huaweiApi(mSource.getContext()); } else if (MARK.contains("xiaomi")) { intent = xiaomiApi(mSource.getContext()); } else if (MARK.contains("oppo")) { intent = oppoApi(mSource.getContext()); } else if (MARK.contains("vivo")) { intent = vivoApi(mSource.getContext()); } else if (MARK.contains("meizu")) { intent = meizuApi(mSource.getContext()); } else { intent = defaultApi(mSource.getContext()); } try { mSource.startActivityForResult(intent, requestCode); } catch (Exception e) { intent = defaultApi(mSource.getContext()); mSource.startActivityForResult(intent, requestCode); } } private static Intent defaultApi(Context context) { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.fromParts("package", context.getPackageName(), null)); return intent; } private static Intent huaweiApi(Context context) { Intent intent = new Intent(); intent.setClassName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity"); if (hasActivity(context, intent)) return intent; return defaultApi(context); } private static Intent xiaomiApi(Context context) { Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR"); intent.putExtra("extra_pkgname", context.getPackageName()); if (hasActivity(context, intent)) return intent; intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity"); if (hasActivity(context, intent)) return intent; intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity"); if (hasActivity(context, intent)) return intent; return defaultApi(context); } private static Intent vivoApi(Context context) { Intent intent = new Intent(); intent.putExtra("packagename", context.getPackageName()); intent.setClassName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.SoftPermissionDetailActivity"); if (hasActivity(context, intent)) return intent; intent.setClassName("com.iqoo.secure", "com.iqoo.secure.safeguard.SoftPermissionDetailActivity"); if (hasActivity(context, intent)) return intent; return defaultApi(context); } private static Intent oppoApi(Context context) { Intent intent = new Intent(); intent.putExtra("packageName", context.getPackageName()); intent.setClassName("com.color.safecenter", "com.color.safecenter.permission.PermissionManagerActivity"); if (hasActivity(context, intent)) return intent; intent.setClassName("com.oppo.safe", "com.oppo.safe.permission.PermissionAppListActivity"); if (hasActivity(context, intent)) return intent; return defaultApi(context); } private static Intent meizuApi(Context context) { Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC"); intent.putExtra("packageName", context.getPackageName()); intent.setClassName("com.meizu.safe", "com.meizu.safe.security.AppSecActivity"); if (hasActivity(context, intent)) return intent; return defaultApi(context); } private static boolean hasActivity(Context context, Intent intent) { PackageManager packageManager = context.getPackageManager(); return packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0; } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/runtime/setting/SettingRequest.java ================================================ /* * Copyright 2018 Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.runtime.setting; /** * Created by Zhenjie Yan on 2018/4/30. */ public interface SettingRequest { /** * Start the setup. */ void start(int requestCode); } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/setting/Setting.java ================================================ /* * Copyright 2019 Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.setting; import android.os.Build; import com.yanzhenjie.permission.setting.write.LWriteRequestFactory; import com.yanzhenjie.permission.setting.write.MWriteRequestFactory; import com.yanzhenjie.permission.setting.write.WriteRequest; import com.yanzhenjie.permission.source.Source; /** * Created by Zhenjie Yan on 3/1/19. */ public class Setting { private static final SettingRequestFactory SETTING_REQUEST_FACTORY; static { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { SETTING_REQUEST_FACTORY = new MWriteRequestFactory(); } else { SETTING_REQUEST_FACTORY = new LWriteRequestFactory(); } } public interface SettingRequestFactory { WriteRequest create(Source source); } private Source mSource; public Setting(Source source) { this.mSource = source; } /** * Handle write system settings. */ public WriteRequest write() { return SETTING_REQUEST_FACTORY.create(mSource); } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/setting/write/BaseRequest.java ================================================ /* * Copyright 2018 Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.setting.write; import android.content.Context; import com.yanzhenjie.permission.Action; import com.yanzhenjie.permission.Rationale; import com.yanzhenjie.permission.RequestExecutor; import com.yanzhenjie.permission.source.Source; /** * Created by Zhenjie Yan on 2018/6/1. */ abstract class BaseRequest implements WriteRequest { private Source mSource; private RationaleContext Wrapper.
* Created by Zhenjie Yan on 2017/5/1. */ public class ActivitySource extends Source { private Activity mActivity; public ActivitySource(Activity activity) { this.mActivity = activity; } @Override public Context getContext() { return mActivity; } @Override public void startActivity(Intent intent) { mActivity.startActivity(intent); } @Override public void startActivityForResult(Intent intent, int requestCode) { mActivity.startActivityForResult(intent, requestCode); } @Override public boolean isShowRationalePermission(String permission) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false; return mActivity.shouldShowRequestPermissionRationale(permission); } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/source/ContextSource.java ================================================ /* * Copyright © Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.source; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import java.lang.reflect.Method; /** *Context Wrapper.
* Created by Zhenjie Yan on 2017/5/1. */ public class ContextSource extends Source { private Context mContext; public ContextSource(Context context) { this.mContext = context; } @Override public Context getContext() { return mContext; } @Override public void startActivity(Intent intent) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } @Override public void startActivityForResult(Intent intent, int requestCode) { throw new UnsupportedOperationException("Unsupported operation."); } @Override public boolean isShowRationalePermission(String permission) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false; PackageManager packageManager = mContext.getPackageManager(); Class> pkManagerClass = packageManager.getClass(); try { Method method = pkManagerClass.getMethod("shouldShowRequestPermissionRationale", String.class); if (!method.isAccessible()) method.setAccessible(true); return (boolean)method.invoke(packageManager, permission); } catch (Exception ignored) { return false; } } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/source/FragmentSource.java ================================================ /* * Copyright © Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.source; import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.os.Build; /** *android.app.Fragment Wrapper.
* Created by Zhenjie Yan on 2017/5/1. */ public class FragmentSource extends Source { private Fragment mFragment; public FragmentSource(Fragment fragment) { this.mFragment = fragment; } @Override public Context getContext() { return mFragment.getActivity(); } @Override public void startActivity(Intent intent) { mFragment.startActivity(intent); } @Override public void startActivityForResult(Intent intent, int requestCode) { mFragment.startActivityForResult(intent, requestCode); } @Override public boolean isShowRationalePermission(String permission) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false; return mFragment.shouldShowRequestPermissionRationale(permission); } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/source/Source.java ================================================ /* * Copyright © Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.source; import android.app.AppOpsManager; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; import androidx.annotation.RequiresApi; import java.lang.reflect.Field; import java.lang.reflect.Method; /** *The source of the request.
* Created by Zhenjie Yan on 2017/5/1. */ public abstract class Source { private static final int MODE_ASK = 4; private static final int MODE_COMPAT = 5; private static final String CHECK_OP_NO_THROW = "checkOpNoThrow"; private static final String OP_REQUEST_INSTALL_PACKAGES = "OP_REQUEST_INSTALL_PACKAGES"; private static final String OP_SYSTEM_ALERT_WINDOW = "OP_SYSTEM_ALERT_WINDOW"; private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"; private static final String OP_ACCESS_NOTIFICATIONS = "OP_ACCESS_NOTIFICATIONS"; private static final String OP_WRITE_SETTINGS = "OP_WRITE_SETTINGS"; private int mTargetSdkVersion; private String mPackageName; private PackageManager mPackageManager; private AppOpsManager mAppOpsManager; private NotificationManager mNotificationManager; public abstract Context getContext(); public abstract void startActivity(Intent intent); public abstract void startActivityForResult(Intent intent, int requestCode); public abstract boolean isShowRationalePermission(String permission); public int getTargetSdkVersion() { if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { mTargetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; } return mTargetSdkVersion; } public String getPackageName() { if (mPackageName == null) { mPackageName = getContext().getApplicationContext().getPackageName(); } return mPackageName; } private PackageManager getPackageManager() { if (mPackageManager == null) { mPackageManager = getContext().getPackageManager(); } return mPackageManager; } @RequiresApi(api = Build.VERSION_CODES.KITKAT) private AppOpsManager getAppOpsManager() { if (mAppOpsManager == null) { mAppOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); } return mAppOpsManager; } private NotificationManager getNotificationManager() { if (mNotificationManager == null) { mNotificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE); } return mNotificationManager; } public final boolean canRequestPackageInstalls() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { return true; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (getTargetSdkVersion() < Build.VERSION_CODES.O) { return reflectionOps(OP_REQUEST_INSTALL_PACKAGES); } return getPackageManager().canRequestPackageInstalls(); } return true; } public final boolean canDrawOverlays() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Context context = getContext(); if (getTargetSdkVersion() >= Build.VERSION_CODES.M) { return Settings.canDrawOverlays(context); } return reflectionOps(OP_SYSTEM_ALERT_WINDOW); } return true; } public final boolean canNotify() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return getNotificationManager().areNotificationsEnabled(); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return reflectionOps(OP_POST_NOTIFICATION); } else { return true; } } public final boolean canListenerNotification() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return reflectionOps(OP_ACCESS_NOTIFICATIONS); } Context context = getContext(); String flat = Settings.Secure.getString(context.getContentResolver(), "enabled_notification_listeners"); return flat != null && flat.contains(getPackageName()); } public final boolean canWriteSetting() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Context context = getContext(); if (getTargetSdkVersion() >= Build.VERSION_CODES.M) { return Settings.System.canWrite(context); } return reflectionOps(OP_WRITE_SETTINGS); } return true; } @RequiresApi(api = Build.VERSION_CODES.KITKAT) private boolean reflectionOps(String opFieldName) { int uid = getContext().getApplicationInfo().uid; try { Classandroid.support.v4.app.Fragment Wrapper.
* Created by Zhenjie Yan on 2017/5/1. */ public class XFragmentSource extends Source { private Fragment mFragment; public XFragmentSource(Fragment fragment) { this.mFragment = fragment; } @Override public Context getContext() { return mFragment.getContext(); } @Override public void startActivity(Intent intent) { mFragment.startActivity(intent); } @Override public void startActivityForResult(Intent intent, int requestCode) { mFragment.startActivityForResult(intent, requestCode); } @Override public boolean isShowRationalePermission(String permission) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false; return mFragment.shouldShowRequestPermissionRationale(permission); } } ================================================ FILE: permission/src/main/java/com/yanzhenjie/permission/task/TaskExecutor.java ================================================ /* * Copyright 2019 Zhenjie Yan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.permission.task; import android.app.Dialog; import android.content.Context; import android.os.AsyncTask; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * Created by Zhenjie Yan on 2019-09-23. */ public abstract class TaskExecutor