diff --git a/api/current.txt b/api/current.txt index c0176c959c74a..977478ee698e6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25738,6 +25738,7 @@ package android.provider { method public static java.lang.String getVersion(android.content.Context); field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE"; + field public static final java.lang.String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM"; field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE"; field public static final java.lang.String AUTHORITY = "media"; field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit"; diff --git a/api/system-current.txt b/api/system-current.txt index 4a2e4027a3c22..a4e379315f1bf 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -27617,6 +27617,7 @@ package android.provider { method public static java.lang.String getVersion(android.content.Context); field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE"; + field public static final java.lang.String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM"; field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE"; field public static final java.lang.String AUTHORITY = "media"; field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit"; diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 5afbd6dfc5769..7565654b7ae7e 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -225,6 +225,35 @@ public final class MediaStore { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA"; + /** + * The name of the Intent action used to indicate that a camera launch might be imminent. This + * broadcast should be targeted to the package that is receiving + * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or + * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE}, depending on the context. If such + * intent would launch the resolver activity, this broadcast should not be sent at all. + *
+ * A receiver of this broadcast should do the absolute minimum amount of work to initialize the + * camera in order to reduce startup time in likely case that shortly after an actual camera + * launch intent would be sent. + *
+ * In case the actual intent will not be fired, the target package will receive + * {@link #ACTION_STILL_IMAGE_CAMERA_COOLDOWN}. However, it is recommended that the receiver + * also implements a timeout to close the camera after receiving this intent, as there is no + * guarantee that {@link #ACTION_STILL_IMAGE_CAMERA_COOLDOWN} will be delivered. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM"; + + /** + * The name of the Intent action used to indicate that an imminent camera launch has been + * cancelled by the user. This broadcast should be targeted to the package that has received + * {@link #ACTION_STILL_IMAGE_CAMERA_PREWARM}. + *
+ * A receiver of this broadcast should close the camera immediately.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_STILL_IMAGE_CAMERA_COOLDOWN = "android.media.action.STILL_IMAGE_CAMERA_COOLDOWN";
+
/**
* The name of the Intent action used to launch a camera in still image mode
* for use when the device is secured (e.g. with a pin, password, pattern,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 3b8fcccb2dbb3..cab152fc74260 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -69,7 +69,7 @@ public class KeyguardAffordanceHelper {
@Override
public void onAnimationEnd(Animator animation) {
mSwipeAnimator = null;
- setSwipingInProgress(false);
+ mSwipingInProgress = false;
}
};
private Runnable mAnimationEndRunnable = new Runnable() {
@@ -117,14 +117,17 @@ public class KeyguardAffordanceHelper {
}
public boolean onTouchEvent(MotionEvent event) {
- if (mMotionCancelled && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+ int action = event.getActionMasked();
+ if (mMotionCancelled && action != MotionEvent.ACTION_DOWN
+ && action != MotionEvent.ACTION_UP
+ && action != MotionEvent.ACTION_CANCEL) {
return false;
}
final float y = event.getY();
final float x = event.getX();
boolean isUp = false;
- switch (event.getActionMasked()) {
+ switch (action) {
case MotionEvent.ACTION_DOWN:
if (mSwipingInProgress) {
cancelAnimation();
@@ -152,7 +155,8 @@ public class KeyguardAffordanceHelper {
mInitialTouchY = y;
mInitialTouchX = x;
mTranslationOnDown = mTranslation;
- setSwipingInProgress(true);
+ mSwipingInProgress = true;
+ mCallback.onSwipingStarted(w < -mTouchSlop);
}
if (mSwipingInProgress) {
setTranslation(mTranslationOnDown + x - mInitialTouchX, false, false);
@@ -179,13 +183,6 @@ public class KeyguardAffordanceHelper {
}
}
- private void setSwipingInProgress(boolean inProgress) {
- mSwipingInProgress = inProgress;
- if (inProgress) {
- mCallback.onSwipingStarted();
- }
- }
-
private boolean rightSwipePossible() {
return mRightIcon.getVisibility() == View.VISIBLE;
}
@@ -323,6 +320,9 @@ public class KeyguardAffordanceHelper {
}
animator.start();
mSwipeAnimator = animator;
+ if (snapBack) {
+ mCallback.onSwipingAborted();
+ }
}
private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable) {
@@ -451,7 +451,11 @@ public class KeyguardAffordanceHelper {
mSwipeAnimator.cancel();
}
setTranslation(0.0f, true, animate);
- setSwipingInProgress(false);
+ mMotionCancelled = true;
+ if (mSwipingInProgress) {
+ mCallback.onSwipingAborted();
+ }
+ mSwipingInProgress = false;
}
public interface Callback {
@@ -470,7 +474,9 @@ public class KeyguardAffordanceHelper {
float getPageWidth();
- void onSwipingStarted();
+ void onSwipingStarted(boolean isRightwardMotion);
+
+ void onSwipingAborted();
KeyguardAffordanceView getLeftIcon();
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 a247c8e8f0742..628ae845fe576 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -100,6 +100,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private final TrustDrawable mTrustDrawable;
private final Interpolator mLinearOutSlowInInterpolator;
private int mLastUnlockIconRes = 0;
+ private boolean mPrewarmSent;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -335,12 +336,47 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser());
}
- public void launchCamera() {
+ public void prewarmCamera() {
Intent intent = getCameraIntent();
+ String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
+ mLockPatternUtils.getCurrentUser());
+ if (targetPackage != null) {
+ Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM);
+ prewarm.setPackage(targetPackage);
+ mPrewarmSent = true;
+ mContext.sendBroadcast(prewarm);
+ }
+ }
+
+ public void maybeCooldownCamera() {
+ if (!mPrewarmSent) {
+ return;
+ }
+ mPrewarmSent = false;
+ Intent intent = getCameraIntent();
+ String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
+ mLockPatternUtils.getCurrentUser());
+ if (targetPackage != null) {
+ Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN);
+ prewarm.setPackage(targetPackage);
+ mContext.sendBroadcast(prewarm);
+ }
+ }
+
+ public void launchCamera() {
+
+ // Reset prewarm state.
+ mPrewarmSent = false;
+ final Intent intent = getCameraIntent();
boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, mLockPatternUtils.getCurrentUser());
if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+ });
} else {
// We need to delay starting the activity because ResolverActivity finishes itself if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 195da465ef671..216730be5d005 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1809,13 +1809,23 @@ public class NotificationPanelView extends PanelView implements
}
@Override
- public void onSwipingStarted() {
- mSecureCameraLaunchManager.onSwipingStarted();
+ public void onSwipingStarted(boolean isRightwardMotion) {
+ boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? isRightwardMotion
+ : !isRightwardMotion;
+ if (!start) {
+ mSecureCameraLaunchManager.onSwipingStarted();
+ mKeyguardBottomArea.prewarmCamera();
+ }
requestDisallowInterceptTouchEvent(true);
mOnlyAffordanceInThisMotion = true;
mQsTracking = false;
}
+ @Override
+ public void onSwipingAborted() {
+ mKeyguardBottomArea.maybeCooldownCamera();
+ }
+
@Override
public KeyguardAffordanceView getLeftIcon() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 34068fddef9dd..0dce82ff011e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -106,15 +107,28 @@ public class PreviewInflater {
public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent,
int currentUserId) {
+ return getTargetPackage(ctx, intent, currentUserId) == null;
+ }
+
+ /**
+ * @return the target package of the intent it resolves to a specific package or {@code null} if
+ * it resolved to the resolver activity
+ */
+ public static String getTargetPackage(Context ctx, Intent intent,
+ int currentUserId) {
PackageManager packageManager = ctx.getPackageManager();
final List