Skip to content

Commit 57f928f

Browse files
author
John Spurlock
committed
Recover from badly behaving 3rd party secure cameras.
Bug:7473953 Change-Id: I8daf18c85d951e03fa1c98dda5f255327f96f0ba
1 parent 0889837 commit 57f928f

File tree

4 files changed

+137
-40
lines changed

4 files changed

+137
-40
lines changed

policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@
4040
public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
4141
private static final String TAG = CameraWidgetFrame.class.getSimpleName();
4242
private static final boolean DEBUG = KeyguardHostView.DEBUG;
43-
private static final int WIDGET_ANIMATION_DURATION = 250;
44-
private static final int WIDGET_WAIT_DURATION = 650;
43+
private static final int WIDGET_ANIMATION_DURATION = 250; // ms
44+
private static final int WIDGET_WAIT_DURATION = 650; // ms
45+
private static final int RECOVERY_DELAY = 1000; // ms
4546

4647
interface Callbacks {
4748
void onLaunchingCamera();
48-
void onCameraLaunched();
49+
void onCameraLaunchedSuccessfully();
50+
void onCameraLaunchedUnsuccessfully();
4951
}
5052

5153
private final Handler mHandler = new Handler();
@@ -59,16 +61,39 @@ interface Callbacks {
5961
private long mLaunchCameraStart;
6062
private boolean mActive;
6163
private boolean mTransitioning;
64+
private boolean mRecovering;
6265
private boolean mDown;
6366

64-
private final Runnable mLaunchCameraRunnable = new Runnable() {
67+
private final Runnable mTransitionToCameraRunnable = new Runnable() {
68+
@Override
69+
public void run() {
70+
transitionToCamera();
71+
}};
72+
73+
private final Runnable mTransitionToCameraEndAction = new Runnable() {
6574
@Override
6675
public void run() {
6776
if (!mTransitioning)
6877
return;
78+
Handler worker = getWorkerHandler() != null ? getWorkerHandler() : mHandler;
6979
mLaunchCameraStart = SystemClock.uptimeMillis();
7080
if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart);
71-
mActivityLauncher.launchCamera();
81+
mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
82+
}};
83+
84+
private final Runnable mRecoverRunnable = new Runnable() {
85+
@Override
86+
public void run() {
87+
recover();
88+
}};
89+
90+
private final Runnable mRecoverEndAction = new Runnable() {
91+
@Override
92+
public void run() {
93+
if (!mRecovering)
94+
return;
95+
mCallbacks.onCameraLaunchedUnsuccessfully();
96+
reset();
7297
}};
7398

7499
private final Runnable mRenderRunnable = new Runnable() {
@@ -77,15 +102,15 @@ public void run() {
77102
render();
78103
}};
79104

80-
private final Runnable mTransitionToCameraRunnable = new Runnable() {
105+
private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() {
81106
@Override
82107
public void run() {
83-
transitionToCamera();
84-
}};
108+
onSecureCameraActivityStarted();
109+
}
110+
};
85111

86112
private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
87113
private boolean mShowing;
88-
89114
void onKeyguardVisibilityChanged(boolean showing) {
90115
if (mShowing == showing)
91116
return;
@@ -97,7 +122,6 @@ void onKeyguardVisibilityChanged(boolean showing) {
97122
private CameraWidgetFrame(Context context, Callbacks callbacks,
98123
KeyguardActivityLauncher activityLauncher) {
99124
super(context);
100-
101125
mCallbacks = callbacks;
102126
mActivityLauncher = activityLauncher;
103127
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -261,12 +285,24 @@ private void transitionToCamera() {
261285
.scaleY(scale)
262286
.translationY(finishCenter - startCenter)
263287
.setDuration(WIDGET_ANIMATION_DURATION)
264-
.withEndAction(mLaunchCameraRunnable)
288+
.withEndAction(mTransitionToCameraEndAction)
265289
.start();
266290

267291
mCallbacks.onLaunchingCamera();
268292
}
269293

294+
private void recover() {
295+
if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
296+
mRecovering = true;
297+
animate()
298+
.scaleX(1)
299+
.scaleY(1)
300+
.translationY(0)
301+
.setDuration(WIDGET_ANIMATION_DURATION)
302+
.withEndAction(mRecoverEndAction)
303+
.start();
304+
}
305+
270306
@Override
271307
public void onClick(View v) {
272308
if (DEBUG) Log.d(TAG, "clicked");
@@ -283,6 +319,8 @@ protected void onDetachedFromWindow() {
283319
+ " at " + SystemClock.uptimeMillis());
284320
super.onDetachedFromWindow();
285321
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
322+
cancelTransitionToCamera();
323+
mHandler.removeCallbacks(mRecoverRunnable);
286324
}
287325

288326
@Override
@@ -320,7 +358,7 @@ public boolean onUserInteraction(MotionEvent event) {
320358

321359
@Override
322360
protected void onFocusLost() {
323-
if (DEBUG) Log.d(TAG, "onFocusLost");
361+
if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis());
324362
cancelTransitionToCamera();
325363
super.onFocusLost();
326364
}
@@ -342,16 +380,18 @@ private void cancelTransitionToCamera() {
342380
}
343381

344382
private void onCameraLaunched() {
345-
mCallbacks.onCameraLaunched();
383+
mCallbacks.onCameraLaunchedSuccessfully();
346384
reset();
347385
}
348386

349387
private void reset() {
350-
if (DEBUG) Log.d(TAG, "reset");
388+
if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
351389
mLaunchCameraStart = 0;
352390
mTransitioning = false;
391+
mRecovering = false;
353392
mDown = false;
354393
cancelTransitionToCamera();
394+
mHandler.removeCallbacks(mRecoverRunnable);
355395
animate().cancel();
356396
setScaleX(1);
357397
setScaleY(1);
@@ -376,7 +416,8 @@ private void enableWindowExitAnimation(boolean isEnabled) {
376416
WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
377417
int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
378418
if (newWindowAnimations != wlp.windowAnimations) {
379-
if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations);
419+
if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations
420+
+ " at " + SystemClock.uptimeMillis());
380421
wlp.windowAnimations = newWindowAnimations;
381422
mWindowManager.updateViewLayout(root, wlp);
382423
}
@@ -387,6 +428,8 @@ private void onKeyguardVisibilityChanged(boolean showing) {
387428
+ " at " + SystemClock.uptimeMillis());
388429
if (mTransitioning && !showing) {
389430
mTransitioning = false;
431+
mRecovering = false;
432+
mHandler.removeCallbacks(mRecoverRunnable);
390433
if (mLaunchCameraStart > 0) {
391434
long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
392435
if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
@@ -396,6 +439,11 @@ private void onKeyguardVisibilityChanged(boolean showing) {
396439
}
397440
}
398441

442+
private void onSecureCameraActivityStarted() {
443+
if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis());
444+
mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY);
445+
}
446+
399447
private String instanceId() {
400448
return Integer.toHexString(hashCode());
401449
}

policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818

1919
import android.app.ActivityManagerNative;
2020
import android.app.ActivityOptions;
21+
import android.app.IActivityManager.WaitResult;
2122
import android.content.ActivityNotFoundException;
2223
import android.content.Context;
2324
import android.content.Intent;
2425
import android.content.pm.PackageManager;
2526
import android.content.pm.ResolveInfo;
2627
import android.os.Bundle;
28+
import android.os.Handler;
2729
import android.os.RemoteException;
2830
import android.os.SystemClock;
2931
import android.os.UserHandle;
@@ -91,7 +93,7 @@ public CameraWidgetInfo getCameraWidgetInfo() {
9193
return info;
9294
}
9395

94-
public void launchCamera() {
96+
public void launchCamera(Handler worker, Runnable onSecureCameraStarted) {
9597
LockPatternUtils lockPatternUtils = getLockPatternUtils();
9698
if (lockPatternUtils.isSecure()) {
9799
// Launch the secure version of the camera
@@ -100,26 +102,33 @@ public void launchCamera() {
100102
// For now, we'll treat this like launching any other app from secure keyguard.
101103
// When they do, user sees the system's ResolverActivity which lets them choose
102104
// which secure camera to use.
103-
launchActivity(SECURE_CAMERA_INTENT, false, false);
105+
launchActivity(SECURE_CAMERA_INTENT, false, false, null, null);
104106
} else {
105-
launchActivity(SECURE_CAMERA_INTENT, true, false);
107+
launchActivity(SECURE_CAMERA_INTENT, true, false, worker, onSecureCameraStarted);
106108
}
107109
} else {
108110
// Launch the normal camera
109-
launchActivity(INSECURE_CAMERA_INTENT, false, false);
111+
launchActivity(INSECURE_CAMERA_INTENT, false, false, null, null);
110112
}
111113
}
112114

113115
/**
114116
* Launches the said intent for the current foreground user.
117+
*
115118
* @param intent
116119
* @param showsWhileLocked true if the activity can be run on top of keyguard.
117-
* See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
120+
* See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
121+
* @param useDefaultAnimations true if default transitions should be used, else suppressed.
122+
* @param worker if supplied along with onStarted, used to launch the blocking activity call.
123+
* @param onStarted if supplied along with worker, called after activity is started.
118124
*/
119-
public void launchActivity(final Intent intent, boolean showsWhileLocked, boolean animate) {
125+
public void launchActivity(final Intent intent,
126+
boolean showsWhileLocked,
127+
boolean useDefaultAnimations,
128+
final Handler worker,
129+
final Runnable onStarted) {
120130
final Context context = getContext();
121-
final Bundle animation = animate ? null :
122-
ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
131+
final Bundle animation = ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
123132
LockPatternUtils lockPatternUtils = getLockPatternUtils();
124133
intent.addFlags(
125134
Intent.FLAG_ACTIVITY_NEW_TASK
@@ -135,8 +144,7 @@ public void launchActivity(final Intent intent, boolean showsWhileLocked, boolea
135144
try {
136145
if (DEBUG) Log.d(TAG, String.format("Starting activity for intent %s at %s",
137146
intent, SystemClock.uptimeMillis()));
138-
context.startActivityAsUser(intent, animation,
139-
new UserHandle(UserHandle.USER_CURRENT));
147+
startActivityForCurrentUser(intent, animation, worker, onStarted);
140148
} catch (ActivityNotFoundException e) {
141149
Log.w(TAG, "Activity not found for intent + " + intent.getAction());
142150
}
@@ -147,14 +155,52 @@ public void launchActivity(final Intent intent, boolean showsWhileLocked, boolea
147155
callback.setOnDismissRunnable(new Runnable() {
148156
@Override
149157
public void run() {
150-
context.startActivityAsUser(intent, animation,
151-
new UserHandle(UserHandle.USER_CURRENT));
158+
startActivityForCurrentUser(intent, animation, worker, onStarted);
152159
}
153160
});
154161
callback.dismiss(false);
155162
}
156163
}
157164

165+
private void startActivityForCurrentUser(final Intent intent, final Bundle options,
166+
Handler worker, final Runnable onStarted) {
167+
final UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
168+
if (worker == null || onStarted == null) {
169+
getContext().startActivityAsUser(intent, options, user);
170+
return;
171+
}
172+
// if worker + onStarted are supplied, run blocking activity launch call in the background
173+
worker.post(new Runnable(){
174+
@Override
175+
public void run() {
176+
try {
177+
WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait(
178+
null /*caller*/,
179+
intent,
180+
intent.resolveTypeIfNeeded(getContext().getContentResolver()),
181+
null /*resultTo*/,
182+
null /*resultWho*/,
183+
0 /*requestCode*/,
184+
Intent.FLAG_ACTIVITY_NEW_TASK,
185+
null /*profileFile*/,
186+
null /*profileFd*/,
187+
options,
188+
user.getIdentifier());
189+
if (DEBUG) Log.d(TAG, String.format("waitResult[%s,%s,%s,%s] at %s",
190+
result.result, result.thisTime, result.totalTime, result.who,
191+
SystemClock.uptimeMillis()));
192+
} catch (RemoteException e) {
193+
Log.w(TAG, "Error starting activity", e);
194+
return;
195+
}
196+
try {
197+
onStarted.run();
198+
} catch (Throwable t) {
199+
Log.w(TAG, "Error running onStarted callback", t);
200+
}
201+
}});
202+
}
203+
158204
private Intent getCameraIntent() {
159205
return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
160206
}

policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -830,26 +830,29 @@ private boolean addWidget(int appId, int pageIndex) {
830830
new CameraWidgetFrame.Callbacks() {
831831
@Override
832832
public void onLaunchingCamera() {
833-
SlidingChallengeLayout slider = locateSlider();
834-
if (slider != null) {
835-
slider.setHandleAlpha(0);
836-
}
833+
setSliderHandleAlpha(0);
837834
}
838835

839836
@Override
840-
public void onCameraLaunched() {
837+
public void onCameraLaunchedSuccessfully() {
841838
if (isCameraPage(mAppWidgetContainer.getCurrentPage())) {
842839
mAppWidgetContainer.scrollLeft();
843840
}
844-
SlidingChallengeLayout slider = locateSlider();
845-
if (slider != null) {
846-
slider.setHandleAlpha(1);
847-
}
841+
setSliderHandleAlpha(1);
848842
mShowSecurityWhenReturn = true;
849843
}
850844

851-
public SlidingChallengeLayout locateSlider() {
852-
return (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
845+
@Override
846+
public void onCameraLaunchedUnsuccessfully() {
847+
setSliderHandleAlpha(1);
848+
}
849+
850+
private void setSliderHandleAlpha(float alpha) {
851+
SlidingChallengeLayout slider =
852+
(SlidingChallengeLayout) findViewById(R.id.sliding_layout);
853+
if (slider != null) {
854+
slider.setHandleAlpha(alpha);
855+
}
853856
}
854857
};
855858

policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ public void onTrigger(View v, int target) {
5959
((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
6060
.getAssistIntent(mContext, UserHandle.USER_CURRENT);
6161
if (assistIntent != null) {
62-
mActivityLauncher.launchActivity(assistIntent, false, true);
62+
mActivityLauncher.launchActivity(assistIntent, false, true, null, null);
6363
} else {
6464
Log.w(TAG, "Failed to get intent for assist activity");
6565
}
6666
mCallback.userActivity(0);
6767
break;
6868

6969
case com.android.internal.R.drawable.ic_lockscreen_camera:
70-
mActivityLauncher.launchCamera();
70+
mActivityLauncher.launchCamera(null, null);
7171
mCallback.userActivity(0);
7272
break;
7373

0 commit comments

Comments
 (0)