Merge "Fix issue #5173952: Opening a Notification From Lock Screen..."
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7799779..b4471f0 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1550,6 +1550,13 @@
             return true;
         }
 
+        case DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            dismissKeyguardOnNextActivity();
+            reply.writeNoException();
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3504,5 +3511,15 @@
         reply.recycle();
     }
 
+    public void dismissKeyguardOnNextActivity() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 27dd691..26813bf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -372,6 +372,8 @@
 
     public void showBootMessage(CharSequence msg, boolean always) throws RemoteException;
 
+    public void dismissKeyguardOnNextActivity() throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -602,4 +604,5 @@
     int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135;
     int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
     int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
+    int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138;
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 72cf26a..f44d038 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5577,24 +5577,35 @@
 
     @Override
     public String toString() {
-        StringBuilder   b = new StringBuilder(128);
+        StringBuilder b = new StringBuilder(128);
 
         b.append("Intent { ");
-        toShortString(b, true, true);
+        toShortString(b, true, true, true);
         b.append(" }");
 
         return b.toString();
     }
 
     /** @hide */
-    public String toShortString(boolean comp, boolean extras) {
-        StringBuilder   b = new StringBuilder(128);
-        toShortString(b, comp, extras);
+    public String toInsecureString() {
+        StringBuilder b = new StringBuilder(128);
+
+        b.append("Intent { ");
+        toShortString(b, false, true, true);
+        b.append(" }");
+
         return b.toString();
     }
 
     /** @hide */
-    public void toShortString(StringBuilder b, boolean comp, boolean extras) {
+    public String toShortString(boolean secure, boolean comp, boolean extras) {
+        StringBuilder b = new StringBuilder(128);
+        toShortString(b, secure, comp, extras);
+        return b.toString();
+    }
+
+    /** @hide */
+    public void toShortString(StringBuilder b, boolean secure, boolean comp, boolean extras) {
         boolean first = true;
         if (mAction != null) {
             b.append("act=").append(mAction);
@@ -5621,19 +5632,8 @@
             }
             first = false;
             b.append("dat=");
-            String scheme = mData.getScheme();
-            if (scheme != null) {
-                if (scheme.equalsIgnoreCase("tel")) {
-                    b.append("tel:xxx-xxx-xxxx");
-                } else if (scheme.equalsIgnoreCase("sip")) {
-                    b.append("sip:xxxxxxxxxx");
-                } else if (scheme.equalsIgnoreCase("sms")) {
-                    b.append("sms:xxx-xxx-xxxx");
-                } else if (scheme.equalsIgnoreCase("smsto")) {
-                    b.append("smsto:xxx-xxx-xxxx");
-                } else {
-                    b.append(mData);
-                }
+            if (secure) {
+                b.append(mData.toSafeString());
             } else {
                 b.append(mData);
             }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 2c875c8..9d28eff 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -353,6 +353,48 @@
     public abstract String toString();
 
     /**
+     * Return a string representation of the URI that is safe to print
+     * to logs and other places where PII should be avoided.
+     * @hide
+     */
+    public String toSafeString() {
+        String scheme = getScheme();
+        String ssp = getSchemeSpecificPart();
+        if (scheme != null) {
+            if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
+                    || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
+                    || scheme.equalsIgnoreCase("mailto")) {
+                StringBuilder builder = new StringBuilder(64);
+                builder.append(scheme);
+                builder.append(':');
+                if (ssp != null) {
+                    for (int i=0; i<ssp.length(); i++) {
+                        char c = ssp.charAt(i);
+                        if (c == '-' || c == '@' || c == '.') {
+                            builder.append(c);
+                        } else {
+                            builder.append('x');
+                        }
+                    }
+                }
+                return builder.toString();
+            }
+        }
+        // Not a sensitive scheme, but let's still be conservative about
+        // the data we include -- only the ssp, not the query params or
+        // fragment, because those can often have sensitive info.
+        StringBuilder builder = new StringBuilder(64);
+        if (scheme != null) {
+            builder.append(scheme);
+            builder.append(':');
+        }
+        if (ssp != null) {
+            builder.append(ssp);
+        }
+        return builder.toString();
+    }
+
+    /**
      * Constructs a new builder, copying the attributes from this Uri.
      */
     public abstract Builder buildUpon();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 55c821d..45f9da2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -116,6 +116,7 @@
     boolean isKeyguardLocked();
     boolean isKeyguardSecure();
     boolean inKeyguardRestrictedInputMode();
+    void dismissKeyguard();
 
     void closeSystemDialogs(String reason);
     
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1dbb083..9c7b2a9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -850,6 +850,11 @@
     public boolean inKeyguardRestrictedKeyInputMode();
 
     /**
+     * Ask the policy to dismiss the keyguard, if it is currently shown.
+     */
+    public void dismissKeyguardLw();
+
+    /**
      * Given an orientation constant, returns the appropriate surface rotation,
      * taking into account sensors, docking mode, rotation lock, and other factors.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index ae447e3..25b1bc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1599,6 +1599,9 @@
                 // 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) {
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index c2f07d6..435aa8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1308,6 +1308,9 @@
                 // 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) {
             }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b0abd97..ee73ed1 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2871,6 +2871,18 @@
         return mKeyguardMediator.isInputRestricted();
     }
 
+    public void dismissKeyguardLw() {
+        if (!mKeyguardMediator.isSecure()) {
+            if (mKeyguardMediator.isShowing()) {
+                mHandler.post(new Runnable() {
+                    public void run() {
+                        mKeyguardMediator.keyguardDone(false, true);
+                    }
+                });
+            }
+        }
+    }
+
     void sendCloseSystemWindows() {
         sendCloseSystemWindows(mContext, null);
     }
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 5ffcdc5..b8c44d9 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -477,7 +477,7 @@
                         : bs.filterStats.entrySet()) {
                     pw.print("    "); pw.print(fe.getValue().count);
                             pw.print(" alarms: ");
-                            pw.println(fe.getKey().getIntent().toShortString(true, false));
+                            pw.println(fe.getKey().getIntent().toShortString(false, true, false));
                 }
             }
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 59ed80f..2942c28 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3784,6 +3784,12 @@
         mWindowManager.showBootMessage(msg, always);
     }
 
+    public void dismissKeyguardOnNextActivity() {
+        synchronized (this) {
+            mMainStack.dismissKeyguardOnNextActivityLocked();
+        }
+    }
+
     final void finishBooting() {
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
@@ -7907,6 +7913,8 @@
         if (dumpAll) {
             pw.println("  mLastPausedActivity: " + mMainStack.mLastPausedActivity);
             pw.println("  mSleepTimeout: " + mMainStack.mSleepTimeout);
+            pw.println("  mDismissKeyguardOnNextActivity: "
+                    + mMainStack.mDismissKeyguardOnNextActivity);
         }
 
         if (mRecentTasks.size() > 0) {
@@ -8547,7 +8555,7 @@
                     for (int i=0; i<N; i++) {
                         sb.setLength(0);
                         sb.append("    Intent: ");
-                        intents.get(i).toShortString(sb, true, false);
+                        intents.get(i).toShortString(sb, false, true, false);
                         pw.println(sb.toString());
                         Bundle bundle = intents.get(i).getExtras();
                         if (bundle != null) {
@@ -8840,7 +8848,8 @@
                 } else if (complete) {
                     // Complete + brief == give a summary.  Isn't that obvious?!?
                     if (lastTask.intent != null) {
-                        pw.print(prefix); pw.print("  "); pw.println(lastTask.intent);
+                        pw.print(prefix); pw.print("  ");
+                                pw.println(lastTask.intent.toInsecureString());
                     }
                 }
             }
@@ -8851,7 +8860,7 @@
                 r.dump(pw, innerPrefix);
             } else if (complete) {
                 // Complete + brief == give a summary.  Isn't that obvious?!?
-                pw.print(innerPrefix); pw.println(r.intent);
+                pw.print(innerPrefix); pw.println(r.intent.toInsecureString());
                 if (r.app != null) {
                     pw.print(innerPrefix); pw.println(r.app);
                 }
@@ -10053,7 +10062,7 @@
         boolean created = false;
         try {
             mStringBuilder.setLength(0);
-            r.intent.getIntent().toShortString(mStringBuilder, false, true);
+            r.intent.getIntent().toShortString(mStringBuilder, true, false, true);
             EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
                     System.identityHashCode(r), r.shortName,
                     mStringBuilder.toString(), r.app.pid);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 73ffafb..ce45bfb1 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -122,7 +122,7 @@
                 pw.print(" processName="); pw.println(processName);
         pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
                 pw.print(" app="); pw.println(app);
-        pw.print(prefix); pw.println(intent);
+        pw.print(prefix); pw.println(intent.toInsecureString());
         pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
                 pw.print(" task="); pw.println(task);
         pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 35dee3c..7bc19ab4 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -259,6 +259,11 @@
      */
     boolean mSleepTimeout = false;
 
+    /**
+     * Dismiss the keyguard after the next activity is displayed?
+     */
+    boolean mDismissKeyguardOnNextActivity = false;
+
     int mThumbnailWidth = -1;
     int mThumbnailHeight = -1;
 
@@ -2169,7 +2174,7 @@
         }
 
         if (err == START_SUCCESS) {
-            Slog.i(TAG, "Starting: " + intent + " from pid "
+            Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
                     + (callerApp != null ? callerApp.pid : callingPid));
         }
 
@@ -2224,6 +2229,7 @@
                     resultRecord, resultWho, requestCode,
                     Activity.RESULT_CANCELED, null);
             }
+            mDismissKeyguardOnNextActivity = false;
             return err;
         }
 
@@ -2235,6 +2241,7 @@
                     resultRecord, resultWho, requestCode,
                     Activity.RESULT_CANCELED, null);
             }
+            mDismissKeyguardOnNextActivity = false;
             String msg;
             if (!aInfo.exported) {
                 msg = "Permission Denial: starting " + intent.toString()
@@ -2272,6 +2279,7 @@
                     }
                     // We pretend to the caller that it was really started, but
                     // they will just get a cancel result.
+                    mDismissKeyguardOnNextActivity = false;
                     return START_SUCCESS;
                 }
             }
@@ -2295,6 +2303,7 @@
                     pal.grantedMode = grantedMode;
                     pal.onlyIfNeeded = onlyIfNeeded;
                     mService.mPendingActivityLaunches.add(pal);
+                    mDismissKeyguardOnNextActivity = false;
                     return START_SWITCHES_CANCELED;
                 }
             }
@@ -2313,8 +2322,17 @@
             mService.doPendingActivityLaunchesLocked(false);
         }
         
-        return startActivityUncheckedLocked(r, sourceRecord,
+        err = startActivityUncheckedLocked(r, sourceRecord,
                 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
+        if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
+            // Someone asked to have the keyguard dismissed on the next
+            // activity start, but we are not actually doing an activity
+            // switch...  just dismiss the keyguard now, because we
+            // probably want to see whatever is behind it.
+            mDismissKeyguardOnNextActivity = false;
+            mService.mWindowManager.dismissKeyguard();
+        }
+        return err;
     }
   
     final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
@@ -2983,6 +3001,11 @@
             w.thisTime = w.totalTime;
         }
         mService.notifyAll();
+
+        if (mDismissKeyguardOnNextActivity) {
+            mDismissKeyguardOnNextActivity = false;
+            mService.mWindowManager.dismissKeyguard();
+        }
     }
 
     void sendActivityResultLocked(int callingUid, ActivityRecord r,
@@ -4126,4 +4149,8 @@
 
         return true;
     }
+    
+    public void dismissKeyguardOnNextActivityLocked() {
+        mDismissKeyguardOnNextActivity = true;
+    }
 }
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java
index 3a5ca66..2618c77 100644
--- a/services/java/com/android/server/am/IntentBindRecord.java
+++ b/services/java/com/android/server/am/IntentBindRecord.java
@@ -54,7 +54,7 @@
 
     void dumpInService(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("intent={");
-                pw.print(intent.getIntent().toShortString(true, false));
+                pw.print(intent.getIntent().toShortString(false, true, false));
                 pw.println('}');
         pw.print(prefix); pw.print("binder="); pw.println(binder);
         pw.print(prefix); pw.print("requested="); pw.print(requested);
@@ -89,7 +89,7 @@
         sb.append(service.shortName);
         sb.append(':');
         if (intent != null) {
-            intent.getIntent().toShortString(sb, false, false);
+            intent.getIntent().toShortString(sb, false, false, false);
         }
         sb.append('}');
         return stringName = sb.toString();
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 8ed0cc1..abd2a1f 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -150,7 +150,8 @@
         public String toString() {
             return "Key{" + typeName() + " pkg=" + packageName
                 + " intent="
-                + (requestIntent != null ? requestIntent.toShortString(true, false) : "<null>")
+                + (requestIntent != null
+                        ? requestIntent.toShortString(false, true, false) : "<null>")
                 + " flags=0x" + Integer.toHexString(flags) + "}";
         }
         
@@ -317,7 +318,7 @@
         }
         if (key.requestIntent != null) {
             pw.print(prefix); pw.print("requestIntent=");
-                    pw.println(key.requestIntent.toShortString(true, true));
+                    pw.println(key.requestIntent.toShortString(false, true, true));
         }
         if (sent || canceled) {
             pw.print(prefix); pw.print("sent="); pw.print(sent);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 004e963..257113b 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -192,7 +192,7 @@
     
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("intent={");
-                pw.print(intent.getIntent().toShortString(true, false));
+                pw.print(intent.getIntent().toShortString(false, true, false));
                 pw.println('}');
         pw.print(prefix); pw.print("packageName="); pw.println(packageName);
         pw.print(prefix); pw.print("processName="); pw.println(processName);
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 87129ea..a860763 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -94,14 +94,14 @@
         if (intent != null) {
             StringBuilder sb = new StringBuilder(128);
             sb.append(prefix); sb.append("intent={");
-            intent.toShortString(sb, true, false);
+            intent.toShortString(sb, false, true, false);
             sb.append('}');
             pw.println(sb.toString());
         }
         if (affinityIntent != null) {
             StringBuilder sb = new StringBuilder(128);
             sb.append(prefix); sb.append("affinityIntent={");
-            affinityIntent.toShortString(sb, true, false);
+            affinityIntent.toShortString(sb, false, true, false);
             sb.append('}');
             pw.println(sb.toString());
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 02b246a..a9ca304 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4525,6 +4525,16 @@
         return mPolicy.isKeyguardSecure();
     }
 
+    public void dismissKeyguard() {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
+        }
+        synchronized(mWindowMap) {
+            mPolicy.dismissKeyguardLw();
+        }
+    }
+
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
             for (int i=mWindows.size()-1; i>=0; i--) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 940b290..5b57266 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -464,4 +464,7 @@
     public int getPreferredOptionsPanelGravity() throws RemoteException {
         return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
     }
+
+    public void dismissKeyguard() {
+    }
 }