diff options
Diffstat (limited to 'java/src/org/kelar/inputmethod/latin/permissions')
3 files changed, 281 insertions, 0 deletions
diff --git a/java/src/org/kelar/inputmethod/latin/permissions/PermissionsActivity.java b/java/src/org/kelar/inputmethod/latin/permissions/PermissionsActivity.java new file mode 100644 index 000000000..5c56a2a10 --- /dev/null +++ b/java/src/org/kelar/inputmethod/latin/permissions/PermissionsActivity.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * 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 org.kelar.inputmethod.latin.permissions; + + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; + +/** + * An activity to help request permissions. It's used when no other activity is available, e.g. in + * InputMethodService. This activity assumes that all permissions are not granted yet. + */ +public final class PermissionsActivity + extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback { + + /** + * Key to retrieve requested permissions from the intent. + */ + public static final String EXTRA_PERMISSION_REQUESTED_PERMISSIONS = "requested_permissions"; + + /** + * Key to retrieve request code from the intent. + */ + public static final String EXTRA_PERMISSION_REQUEST_CODE = "request_code"; + + private static final int INVALID_REQUEST_CODE = -1; + + private int mPendingRequestCode = INVALID_REQUEST_CODE; + + /** + * Starts a PermissionsActivity and checks/requests supplied permissions. + */ + public static void run( + @NonNull Context context, int requestCode, @NonNull String... permissionStrings) { + Intent intent = new Intent(context.getApplicationContext(), PermissionsActivity.class); + intent.putExtra(EXTRA_PERMISSION_REQUESTED_PERMISSIONS, permissionStrings); + intent.putExtra(EXTRA_PERMISSION_REQUEST_CODE, requestCode); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mPendingRequestCode = (savedInstanceState != null) + ? savedInstanceState.getInt(EXTRA_PERMISSION_REQUEST_CODE, INVALID_REQUEST_CODE) + : INVALID_REQUEST_CODE; + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(EXTRA_PERMISSION_REQUEST_CODE, mPendingRequestCode); + } + + @Override + protected void onResume() { + super.onResume(); + // Only do request when there is no pending request to avoid duplicated requests. + if (mPendingRequestCode == INVALID_REQUEST_CODE) { + final Bundle extras = getIntent().getExtras(); + final String[] permissionsToRequest = + extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS); + mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE); + // Assuming that all supplied permissions are not granted yet, so that we don't need to + // check them again. + PermissionsUtil.requestPermissions(this, mPendingRequestCode, permissionsToRequest); + } + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + mPendingRequestCode = INVALID_REQUEST_CODE; + PermissionsManager.get(this).onRequestPermissionsResult( + requestCode, permissions, grantResults); + finish(); + } +} diff --git a/java/src/org/kelar/inputmethod/latin/permissions/PermissionsManager.java b/java/src/org/kelar/inputmethod/latin/permissions/PermissionsManager.java new file mode 100644 index 000000000..d95f4540d --- /dev/null +++ b/java/src/org/kelar/inputmethod/latin/permissions/PermissionsManager.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * 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 org.kelar.inputmethod.latin.permissions; + +import android.app.Activity; +import android.content.Context; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Manager to perform permission related tasks. Always call on the UI thread. + */ +public class PermissionsManager { + + public interface PermissionsResultCallback { + void onRequestPermissionsResult(boolean allGranted); + } + + private int mRequestCodeId; + + private final Context mContext; + private final Map<Integer, PermissionsResultCallback> mRequestIdToCallback = new HashMap<>(); + + private static PermissionsManager sInstance; + + public PermissionsManager(Context context) { + mContext = context; + } + + @Nonnull + public static synchronized PermissionsManager get(@Nonnull Context context) { + if (sInstance == null) { + sInstance = new PermissionsManager(context); + } + return sInstance; + } + + private synchronized int getNextRequestId() { + return ++mRequestCodeId; + } + + + public synchronized void requestPermissions(@Nonnull PermissionsResultCallback callback, + @Nullable Activity activity, + String... permissionsToRequest) { + List<String> deniedPermissions = PermissionsUtil.getDeniedPermissions( + mContext, permissionsToRequest); + if (deniedPermissions.isEmpty()) { + return; + } + // otherwise request the permissions. + int requestId = getNextRequestId(); + String[] permissionsArray = deniedPermissions.toArray( + new String[deniedPermissions.size()]); + + mRequestIdToCallback.put(requestId, callback); + if (activity != null) { + PermissionsUtil.requestPermissions(activity, requestId, permissionsArray); + } else { + PermissionsActivity.run(mContext, requestId, permissionsArray); + } + } + + public synchronized void onRequestPermissionsResult( + int requestCode, String[] permissions, int[] grantResults) { + PermissionsResultCallback permissionsResultCallback = mRequestIdToCallback.get(requestCode); + mRequestIdToCallback.remove(requestCode); + + boolean allGranted = PermissionsUtil.allGranted(grantResults); + permissionsResultCallback.onRequestPermissionsResult(allGranted); + } +} diff --git a/java/src/org/kelar/inputmethod/latin/permissions/PermissionsUtil.java b/java/src/org/kelar/inputmethod/latin/permissions/PermissionsUtil.java new file mode 100644 index 000000000..337334485 --- /dev/null +++ b/java/src/org/kelar/inputmethod/latin/permissions/PermissionsUtil.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * 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 org.kelar.inputmethod.latin.permissions; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class for permissions. + */ +public class PermissionsUtil { + + /** + * Returns the list of permissions not granted from the given list of permissions. + * @param context Context + * @param permissions list of permissions to check. + * @return the list of permissions that do not have permission to use. + */ + public static List<String> getDeniedPermissions(Context context, + String... permissions) { + final List<String> deniedPermissions = new ArrayList<>(); + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(context, permission) + != PackageManager.PERMISSION_GRANTED) { + deniedPermissions.add(permission); + } + } + return deniedPermissions; + } + + /** + * Uses the given activity and requests the user for permissions. + * @param activity activity to use. + * @param requestCode request code/id to use. + * @param permissions String array of permissions that needs to be requested. + */ + public static void requestPermissions(Activity activity, int requestCode, + String[] permissions) { + ActivityCompat.requestPermissions(activity, permissions, requestCode); + } + + /** + * Checks if all the permissions are granted. + */ + public static boolean allGranted(@NonNull int[] grantResults) { + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + /** + * Queries if al the permissions are granted for the given permission strings. + */ + public static boolean checkAllPermissionsGranted(Context context, String... permissions) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + // For all pre-M devices, we should have all the premissions granted on install. + return true; + } + + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(context, permission) + != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } +} |