Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57f928fc authored by John Spurlock's avatar John Spurlock
Browse files

Recover from badly behaving 3rd party secure cameras.

Bug:7473953
Change-Id: I8daf18c85d951e03fa1c98dda5f255327f96f0ba
parent 08898375
Loading
Loading
Loading
Loading
+63 −15
Original line number Diff line number Diff line
@@ -40,12 +40,14 @@ import com.android.internal.policy.impl.keyguard.KeyguardActivityLauncher.Camera
public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
    private static final String TAG = CameraWidgetFrame.class.getSimpleName();
    private static final boolean DEBUG = KeyguardHostView.DEBUG;
    private static final int WIDGET_ANIMATION_DURATION = 250;
    private static final int WIDGET_WAIT_DURATION = 650;
    private static final int WIDGET_ANIMATION_DURATION = 250; // ms
    private static final int WIDGET_WAIT_DURATION = 650; // ms
    private static final int RECOVERY_DELAY = 1000; // ms

    interface Callbacks {
        void onLaunchingCamera();
        void onCameraLaunched();
        void onCameraLaunchedSuccessfully();
        void onCameraLaunchedUnsuccessfully();
    }

    private final Handler mHandler = new Handler();
@@ -59,16 +61,39 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
    private long mLaunchCameraStart;
    private boolean mActive;
    private boolean mTransitioning;
    private boolean mRecovering;
    private boolean mDown;

    private final Runnable mLaunchCameraRunnable = new Runnable() {
    private final Runnable mTransitionToCameraRunnable = new Runnable() {
        @Override
        public void run() {
            transitionToCamera();
        }};

    private final Runnable mTransitionToCameraEndAction = new Runnable() {
        @Override
        public void run() {
            if (!mTransitioning)
                return;
            Handler worker =  getWorkerHandler() != null ? getWorkerHandler() : mHandler;
            mLaunchCameraStart = SystemClock.uptimeMillis();
            if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart);
            mActivityLauncher.launchCamera();
            mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
        }};

    private final Runnable mRecoverRunnable = new Runnable() {
        @Override
        public void run() {
            recover();
        }};

    private final Runnable mRecoverEndAction = new Runnable() {
        @Override
        public void run() {
            if (!mRecovering)
                return;
            mCallbacks.onCameraLaunchedUnsuccessfully();
            reset();
        }};

    private final Runnable mRenderRunnable = new Runnable() {
@@ -77,15 +102,15 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
            render();
        }};

    private final Runnable mTransitionToCameraRunnable = new Runnable() {
    private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() {
        @Override
        public void run() {
            transitionToCamera();
        }};
            onSecureCameraActivityStarted();
        }
    };

    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
        private boolean mShowing;

        void onKeyguardVisibilityChanged(boolean showing) {
            if (mShowing == showing)
                return;
@@ -97,7 +122,6 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
    private CameraWidgetFrame(Context context, Callbacks callbacks,
            KeyguardActivityLauncher activityLauncher) {
        super(context);

        mCallbacks = callbacks;
        mActivityLauncher = activityLauncher;
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -261,12 +285,24 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
            .scaleY(scale)
            .translationY(finishCenter - startCenter)
            .setDuration(WIDGET_ANIMATION_DURATION)
            .withEndAction(mLaunchCameraRunnable)
            .withEndAction(mTransitionToCameraEndAction)
            .start();

        mCallbacks.onLaunchingCamera();
    }

    private void recover() {
        if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
        mRecovering = true;
        animate()
            .scaleX(1)
            .scaleY(1)
            .translationY(0)
            .setDuration(WIDGET_ANIMATION_DURATION)
            .withEndAction(mRecoverEndAction)
            .start();
    }

    @Override
    public void onClick(View v) {
        if (DEBUG) Log.d(TAG, "clicked");
@@ -283,6 +319,8 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
                + " at " + SystemClock.uptimeMillis());
        super.onDetachedFromWindow();
        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
        cancelTransitionToCamera();
        mHandler.removeCallbacks(mRecoverRunnable);
    }

    @Override
@@ -320,7 +358,7 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli

    @Override
    protected void onFocusLost() {
        if (DEBUG) Log.d(TAG, "onFocusLost");
        if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis());
        cancelTransitionToCamera();
        super.onFocusLost();
    }
@@ -342,16 +380,18 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
    }

    private void onCameraLaunched() {
        mCallbacks.onCameraLaunched();
        mCallbacks.onCameraLaunchedSuccessfully();
        reset();
    }

    private void reset() {
        if (DEBUG) Log.d(TAG, "reset");
        if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
        mLaunchCameraStart = 0;
        mTransitioning = false;
        mRecovering = false;
        mDown = false;
        cancelTransitionToCamera();
        mHandler.removeCallbacks(mRecoverRunnable);
        animate().cancel();
        setScaleX(1);
        setScaleY(1);
@@ -376,7 +416,8 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
        WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
        int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
        if (newWindowAnimations != wlp.windowAnimations) {
            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations);
            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations
                    + " at " + SystemClock.uptimeMillis());
            wlp.windowAnimations = newWindowAnimations;
            mWindowManager.updateViewLayout(root, wlp);
        }
@@ -387,6 +428,8 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
                + " at " + SystemClock.uptimeMillis());
        if (mTransitioning && !showing) {
          mTransitioning = false;
          mRecovering = false;
          mHandler.removeCallbacks(mRecoverRunnable);
          if (mLaunchCameraStart > 0) {
              long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
              if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
@@ -396,6 +439,11 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
        }
    }

    private void onSecureCameraActivityStarted() {
        if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis());
        mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY);
    }

    private String instanceId() {
        return Integer.toHexString(hashCode());
    }
+58 −12
Original line number Diff line number Diff line
@@ -18,12 +18,14 @@ package com.android.internal.policy.impl.keyguard;

import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.IActivityManager.WaitResult;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -91,7 +93,7 @@ public abstract class KeyguardActivityLauncher {
        return info;
    }

    public void launchCamera() {
    public void launchCamera(Handler worker, Runnable onSecureCameraStarted) {
        LockPatternUtils lockPatternUtils = getLockPatternUtils();
        if (lockPatternUtils.isSecure()) {
            // Launch the secure version of the camera
@@ -100,26 +102,33 @@ public abstract class KeyguardActivityLauncher {
                // For now, we'll treat this like launching any other app from secure keyguard.
                // When they do, user sees the system's ResolverActivity which lets them choose
                // which secure camera to use.
                launchActivity(SECURE_CAMERA_INTENT, false, false);
                launchActivity(SECURE_CAMERA_INTENT, false, false, null, null);
            } else {
                launchActivity(SECURE_CAMERA_INTENT, true, false);
                launchActivity(SECURE_CAMERA_INTENT, true, false, worker, onSecureCameraStarted);
            }
        } else {
            // Launch the normal camera
            launchActivity(INSECURE_CAMERA_INTENT, false, false);
            launchActivity(INSECURE_CAMERA_INTENT, false, false, null, null);
        }
    }

    /**
     * Launches the said intent for the current foreground user.
     *
     * @param intent
     * @param showsWhileLocked true if the activity can be run on top of keyguard.
     *   See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
     * @param useDefaultAnimations true if default transitions should be used, else suppressed.
     * @param worker if supplied along with onStarted, used to launch the blocking activity call.
     * @param onStarted if supplied along with worker, called after activity is started.
     */
    public void launchActivity(final Intent intent, boolean showsWhileLocked, boolean animate) {
    public void launchActivity(final Intent intent,
            boolean showsWhileLocked,
            boolean useDefaultAnimations,
            final Handler worker,
            final Runnable onStarted) {
        final Context context = getContext();
        final Bundle animation = animate ? null :
                ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
        final Bundle animation = ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
        LockPatternUtils lockPatternUtils = getLockPatternUtils();
        intent.addFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK
@@ -135,8 +144,7 @@ public abstract class KeyguardActivityLauncher {
            try {
                if (DEBUG) Log.d(TAG, String.format("Starting activity for intent %s at %s",
                        intent, SystemClock.uptimeMillis()));
                context.startActivityAsUser(intent, animation,
                        new UserHandle(UserHandle.USER_CURRENT));
                startActivityForCurrentUser(intent, animation, worker, onStarted);
            } catch (ActivityNotFoundException e) {
                Log.w(TAG, "Activity not found for intent + " + intent.getAction());
            }
@@ -147,14 +155,52 @@ public abstract class KeyguardActivityLauncher {
            callback.setOnDismissRunnable(new Runnable() {
                @Override
                public void run() {
                    context.startActivityAsUser(intent, animation,
                            new UserHandle(UserHandle.USER_CURRENT));
                    startActivityForCurrentUser(intent, animation, worker, onStarted);
                }
            });
            callback.dismiss(false);
        }
    }

    private void startActivityForCurrentUser(final Intent intent, final Bundle options,
            Handler worker, final Runnable onStarted) {
        final UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
        if (worker == null || onStarted == null) {
            getContext().startActivityAsUser(intent, options, user);
            return;
        }
        // if worker + onStarted are supplied, run blocking activity launch call in the background
        worker.post(new Runnable(){
            @Override
            public void run() {
                try {
                    WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait(
                            null /*caller*/,
                            intent,
                            intent.resolveTypeIfNeeded(getContext().getContentResolver()),
                            null /*resultTo*/,
                            null /*resultWho*/,
                            0 /*requestCode*/,
                            Intent.FLAG_ACTIVITY_NEW_TASK,
                            null /*profileFile*/,
                            null /*profileFd*/,
                            options,
                            user.getIdentifier());
                    if (DEBUG) Log.d(TAG, String.format("waitResult[%s,%s,%s,%s] at %s",
                            result.result, result.thisTime, result.totalTime, result.who,
                            SystemClock.uptimeMillis()));
                } catch (RemoteException e) {
                    Log.w(TAG, "Error starting activity", e);
                    return;
                }
                try {
                    onStarted.run();
                } catch (Throwable t) {
                    Log.w(TAG, "Error running onStarted callback", t);
                }
            }});
    }

    private Intent getCameraIntent() {
        return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
    }
+14 −11
Original line number Diff line number Diff line
@@ -830,26 +830,29 @@ public class KeyguardHostView extends KeyguardViewBase {
        new CameraWidgetFrame.Callbacks() {
            @Override
            public void onLaunchingCamera() {
                SlidingChallengeLayout slider = locateSlider();
                if (slider != null) {
                    slider.setHandleAlpha(0);
                }
                setSliderHandleAlpha(0);
            }

            @Override
            public void onCameraLaunched() {
            public void onCameraLaunchedSuccessfully() {
                if (isCameraPage(mAppWidgetContainer.getCurrentPage())) {
                    mAppWidgetContainer.scrollLeft();
                }
                SlidingChallengeLayout slider = locateSlider();
                if (slider != null) {
                    slider.setHandleAlpha(1);
                }
                setSliderHandleAlpha(1);
                mShowSecurityWhenReturn = true;
            }

            public SlidingChallengeLayout locateSlider() {
                return (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
            @Override
            public void onCameraLaunchedUnsuccessfully() {
                setSliderHandleAlpha(1);
            }

            private void setSliderHandleAlpha(float alpha) {
                SlidingChallengeLayout slider =
                        (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
                if (slider != null) {
                    slider.setHandleAlpha(alpha);
                }
            }
        };

+2 −2
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
                            ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
                            .getAssistIntent(mContext, UserHandle.USER_CURRENT);
                    if (assistIntent != null) {
                        mActivityLauncher.launchActivity(assistIntent, false, true);
                        mActivityLauncher.launchActivity(assistIntent, false, true, null, null);
                    } else {
                        Log.w(TAG, "Failed to get intent for assist activity");
                    }
@@ -67,7 +67,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
                    break;

                case com.android.internal.R.drawable.ic_lockscreen_camera:
                    mActivityLauncher.launchCamera();
                    mActivityLauncher.launchCamera(null, null);
                    mCallback.userActivity(0);
                    break;