DO NOT MERGE Only send notification activity intents after dismissing Keyguard

Defers delivery of contentIntent and activity actions until
the lockscreen has been dismissed, so that activities don't
launch beneath it.

Bug: 14491010
Change-Id: Ic8c61c18a75d4f0da2d82a0a8a038a5d98ebb71f
(cherry picked from commit 79f640dd0d02c1cc199937b160d8f7abd3c1eaeb)
This commit is contained in:
Adrian Roos
2014-05-21 13:10:23 +02:00
committed by Jorim Jaggi
parent 49a6e1b321
commit 7d7090d666
5 changed files with 119 additions and 59 deletions

View File

@@ -112,7 +112,9 @@ public class KeyguardHostView extends KeyguardViewBase {
}
public interface OnDismissAction {
/* returns true if the dismiss should be deferred */
/**
* @return true if the dismiss should be deferred
*/
boolean onDismiss();
}

View File

@@ -84,6 +84,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener {
public static final String TAG = "StatusBar";
@@ -213,33 +215,47 @@ public abstract class BaseStatusBar extends SystemUI implements
private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
public boolean onClickHandler(
final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
if (DEBUG) {
Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
}
final boolean isActivity = pendingIntent.isActivity();
if (isActivity) {
try {
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
ActivityManagerNative.getDefault().resumeAppSwitches();
// Also, notifications can be launched from the lock screen,
// so dismiss the lock screen when the activity starts.
ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
} catch (RemoteException e) {
}
}
startNotificationActivity(new OnDismissAction() {
@Override
public boolean onDismiss() {
try {
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
ActivityManagerNative.getDefault().resumeAppSwitches();
// Also, notifications can be launched from the lock screen,
// so dismiss the lock screen when the activity starts.
ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
} catch (RemoteException e) {
}
boolean handled = super.onClickHandler(view, pendingIntent, fillInIntent);
boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
if (isActivity && handled) {
// close the shade if it was open
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
// close the shade if it was open
if (handled) {
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
}
return handled; // Wait for activity start.
}
});
return true;
} else {
return super.onClickHandler(view, pendingIntent, fillInIntent);
}
return handled;
}
private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
return super.onClickHandler(view, pendingIntent, fillInIntent);
}
};
@@ -434,6 +450,14 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
/**
* Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
* @param action A dismiss action that is called if it's safe to start the activity.
*/
protected void startNotificationActivity(OnDismissAction action) {
action.onDismiss();
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
final Locale locale = mContext.getResources().getConfiguration().locale;
@@ -999,47 +1023,55 @@ public abstract class BaseStatusBar extends SystemUI implements
mIsHeadsUp = forHun;
}
public void onClick(View v) {
try {
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
ActivityManagerNative.getDefault().resumeAppSwitches();
// Also, notifications can be launched from the lock screen,
// so dismiss the lock screen when the activity starts.
ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
} catch (RemoteException e) {
}
public void onClick(final View v) {
startNotificationActivity(new OnDismissAction() {
public boolean onDismiss() {
try {
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
ActivityManagerNative.getDefault().resumeAppSwitches();
// Also, notifications can be launched from the lock screen,
// so dismiss the lock screen when the activity starts.
ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
} catch (RemoteException e) {
}
if (mIntent != null) {
int[] pos = new int[2];
v.getLocationOnScreen(pos);
Intent overlay = new Intent();
overlay.setSourceBounds(
new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
try {
mIntent.send(mContext, 0, overlay);
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here. Just log the exception message.
Log.w(TAG, "Sending contentIntent failed: " + e);
boolean sent = false;
if (mIntent != null) {
int[] pos = new int[2];
v.getLocationOnScreen(pos);
Intent overlay = new Intent();
overlay.setSourceBounds(new Rect(pos[0], pos[1],
pos[0]+v.getWidth(), pos[1]+v.getHeight()));
try {
mIntent.send(mContext, 0, overlay);
sent = true;
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
Log.w(TAG, "Sending contentIntent failed: " + e);
}
}
try {
if (mIsHeadsUp) {
mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
}
mBarService.onNotificationClick(mNotificationKey);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
// close the shade if it was open
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
boolean waitForActivityLaunch = sent && mIntent.isActivity();
return waitForActivityLaunch;
}
KeyguardTouchDelegate.getInstance(mContext).dismiss();
}
try {
if (mIsHeadsUp) {
mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
}
mBarService.onNotificationClick(mNotificationKey);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
// close the shade if it was open
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
});
}
}

View File

@@ -28,6 +28,7 @@ import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.keyguard.KeyguardViewMediator;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.*;
/**
@@ -69,6 +70,12 @@ public class KeyguardBouncer {
}
}
public void showWithDismissAction(OnDismissAction r) {
ensureView();
mKeyguardView.setOnDismissAction(r);
show();
}
public void hide() {
if (mKeyguardView != null) {
mKeyguardView.cleanUp();

View File

@@ -22,6 +22,7 @@ import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
@@ -2346,6 +2347,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
@Override
protected void startNotificationActivity(OnDismissAction action) {
if (mStatusBarKeyguardViewManager.isShowing()) {
mStatusBarKeyguardViewManager.dismissWithAction(action);
} else {
action.onDismiss();
}
}
// SystemUIService notifies SystemBars of configuration changes, which then calls down here
@Override
protected void onConfigurationChanged(Configuration newConfig) {

View File

@@ -29,6 +29,8 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
* via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
@@ -108,6 +110,13 @@ public class StatusBarKeyguardViewManager {
updateStates();
}
public void dismissWithAction(OnDismissAction r) {
if (!mOccluded) {
mBouncer.showWithDismissAction(r);
}
updateStates();
}
/**
* Reset the state of the view.
*/