diff options
5 files changed, 97 insertions, 13 deletions
diff --git a/packages/SystemUI/docs/camera.md b/packages/SystemUI/docs/camera.md index 7a7a5aa3eb7f..cabc65c53caa 100644 --- a/packages/SystemUI/docs/camera.md +++ b/packages/SystemUI/docs/camera.md @@ -13,8 +13,8 @@ _as of august 2020_ 4. Inside SystemUI, [onCameraLaunchDetected](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3927) looks at the keyguard state and determines 1. whether the camera is even allowed 2. whether the screen is on; if not, we need to delay until that happens - 3. whether the device is locked (defined as "keyuguard is showing"). -5. If the device is unlocked (no keyguard), the camera is launched immediately. [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3949). + 3. whether the device is locked (defined as "keyguard is showing"). +5. If the device is unlocked (no keyguard), the camera is launched immediately. [Callsite in onCameraLaunchGestureDetected](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#4047). 6. If the keyguard is up, however, [KeyguardBottomAreaView.launchCamera](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#477) takes over to handle the "secure camera" (a different intent, usually directing to the same app, but giving that app the cue to not allow access to the photo roll, etc). 7. If the intent [would have to launch a resolver](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#480) (the user has multiple cameras installed and hasn’t chosen one to always launch for the `SECURE_CAMERA_INTENT`), 1. In order to show the resolver, the lockscreen "bouncer" (authentication method) [is first presented](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523). @@ -26,8 +26,9 @@ _as of august 2020_ * If the keyguard is not showing (device is unlocked) - * `KeyguardBottomAreaView.INSECURE_CAMERA_INTENT`, defined to be `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA`. + * `CameraIntents.getInsecureCameraIntent()`, defined to be `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA`. * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3950) in StatusBar.java. * If the keyguard is showing (device locked) - * [KeyguardBottomAreaView.getCameraIntent()](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#366) is consulted, which allows the "keyguard right button" (which we don’t actually show) to control the camera intent. The [default implementation](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#831) returns one of `KeyguardBottomAreaView.INSECURE_CAMERA_INTENT` or `KeyguardBottomAreaView.SECURE_CAMERA_INTENT`, which are `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA` and `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE`, respectively. + * [KeyguardBottomAreaView.getCameraIntent()](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#366) is consulted, which allows the "keyguard right button" (which we don’t actually show) to control the camera intent. The [default implementation](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#831) returns one of `CameraIntents.getInsecureCameraIntent()` or `CameraIntents.getSecureCameraIntent()`, which are `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA` and `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE`, respectively. * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523) in KeyguardBottomAreaView.java. +* Note that starting in Android 12, as required by some OEMs, if the special string resource `config_cameraGesturePackage` is nonempty, this will be treated as a package name to be added to the insecure camera intent, constraining the invocation to that single app and typically preventing implicit intent resolution. This package must be on the device or the camera gesture will no longer work properly.
\ No newline at end of file diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 6e61148f4ac8..d37d2392d0b7 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -589,6 +589,10 @@ <!-- Determines whether the shell features all run on another thread. --> <bool name="config_enableShellMainThread">false</bool> + <!-- package name of a built-in camera app to use to restrict implicit intent resolution + when the double-press power gesture is used. Ignored if empty. --> + <string translatable="false" name="config_cameraGesturePackage"></string> + <!-- Determines whether to allow the nav bar handle to be forced to be opaque. --> <bool name="allow_force_nav_bar_handle_opaque">true</bool> diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt new file mode 100644 index 000000000000..464bee18f030 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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 com.android.systemui.camera + +import android.content.Context +import android.content.Intent +import android.provider.MediaStore +import android.text.TextUtils + +import com.android.systemui.R + +interface CameraIntents { + companion object { + const val DEFAULT_SECURE_CAMERA_INTENT_ACTION = + MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE + const val DEFAULT_INSECURE_CAMERA_INTENT_ACTION = + MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA + + @JvmStatic + fun getOverrideCameraPackage(context: Context): String? { + context.resources.getString(R.string.config_cameraGesturePackage)?.let { + if (!TextUtils.isEmpty(it)) { + return it + } + } + return null + } + + @JvmStatic + fun getInsecureCameraIntent(context: Context): Intent { + val intent = Intent(DEFAULT_INSECURE_CAMERA_INTENT_ACTION) + getOverrideCameraPackage(context)?.let { + intent.setPackage(it) + } + return intent + } + + @JvmStatic + fun getSecureCameraIntent(context: Context): Intent { + val intent = Intent(DEFAULT_SECURE_CAMERA_INTENT_ACTION) + getOverrideCameraPackage(context)?.let { + intent.setPackage(it) + } + return intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + } + + @JvmStatic + fun isSecureCameraIntent(intent: Intent): Boolean { + return intent.getAction().equals(DEFAULT_SECURE_CAMERA_INTENT_ACTION) + } + + @JvmStatic + fun isInsecureCameraIntent(intent: Intent): Boolean { + return intent.getAction().equals(DEFAULT_INSECURE_CAMERA_INTENT_ACTION) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 80109cb7a06c..b891e6f4552c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -73,6 +73,7 @@ import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.assist.AssistManager; +import com.android.systemui.camera.CameraIntents; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.IntentButtonProvider; import com.android.systemui.plugins.IntentButtonProvider.IntentButton; @@ -110,11 +111,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private static final String RIGHT_BUTTON_PLUGIN = "com.android.systemui.action.PLUGIN_LOCKSCREEN_RIGHT_BUTTON"; - private static final Intent SECURE_CAMERA_INTENT = - new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) - .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - public static final Intent INSECURE_CAMERA_INTENT = - new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL); private static final int DOZE_ANIMATION_STAGGER_DELAY = 48; private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250; @@ -498,7 +494,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source); boolean wouldLaunchResolverActivity = mActivityIntentHelper.wouldLaunchResolverActivity( intent, KeyguardUpdateMonitor.getCurrentUser()); - if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) { + if (CameraIntents.isSecureCameraIntent(intent) && !wouldLaunchResolverActivity) { AsyncTask.execute(new Runnable() { @Override public void run() { @@ -855,7 +851,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public Intent getIntent() { boolean canDismissLs = mKeyguardStateController.canDismissLockScreen(); boolean secure = mKeyguardStateController.isMethodSecure(); - return (secure && !canDismissLs) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; + if (secure && !canDismissLs) { + return CameraIntents.getSecureCameraIntent(getContext()); + } else { + return CameraIntents.getInsecureCameraIntent(getContext()); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d581c4b6f9b7..bac5a91c17ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -150,6 +150,7 @@ import com.android.systemui.SystemUI; import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.camera.CameraIntents; import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -2662,6 +2663,12 @@ public class StatusBar extends SystemUI implements DemoMode, for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) { pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); } + + pw.println("Camera gesture intents:"); + pw.println(" Insecure camera: " + CameraIntents.getInsecureCameraIntent(mContext)); + pw.println(" Secure camera: " + CameraIntents.getSecureCameraIntent(mContext)); + pw.println(" Override package: " + + String.valueOf(CameraIntents.getOverrideCameraPackage(mContext))); } public static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { @@ -2734,7 +2741,7 @@ public class StatusBar extends SystemUI implements DemoMode, null /* remoteAnimation */)); options.setDisallowEnterPictureInPictureWhileLaunching( disallowEnterPictureInPictureWhileLaunching); - if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { + if (CameraIntents.isInsecureCameraIntent(intent)) { // Normally an activity will set it's requested rotation // animation on its window. However when launching an activity // causes the orientation to change this is too late. In these cases @@ -4023,7 +4030,8 @@ public class StatusBar extends SystemUI implements DemoMode, } if (!mStatusBarKeyguardViewManager.isShowing()) { - startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT, + final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext); + startActivityDismissingKeyguard(cameraIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0); } else { |