Merge "Wire up caller chooser targets for ChooserActivity" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index eb69ed6..df77416 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5781,6 +5781,7 @@
     method public void setPasswordQuality(android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
+    method public void setPreferredSetupActivity(android.content.ComponentName, android.content.ComponentName);
     method public void setProfileEnabled(android.content.ComponentName);
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
diff --git a/api/system-current.txt b/api/system-current.txt
index b8c7fa2..e10a8b2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5886,6 +5886,7 @@
     method public void setPasswordQuality(android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
+    method public void setPreferredSetupActivity(android.content.ComponentName, android.content.ComponentName);
     method public void setProfileEnabled(android.content.ComponentName);
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b11c509..a71a258 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2521,6 +2521,15 @@
             return true;
         }
 
+        case UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            ComponentName preferredActivity = ComponentName.readFromParcel(data);
+            int userId = data.readInt();
+            updatePreferredSetupActivity(preferredActivity, userId);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_PACKAGE_PROCESS_STATE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
@@ -5821,6 +5830,20 @@
     }
 
     @Override
+    public void updatePreferredSetupActivity(ComponentName preferredActivity, int userId)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        ComponentName.writeToParcel(preferredActivity, data);
+        data.writeInt(userId);
+        mRemote.transact(UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
     public int getPackageProcessState(String packageName) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 00558fe..5829fbe 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -496,6 +496,8 @@
             throws RemoteException;
     public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;
     public void updateDeviceOwner(String packageName) throws RemoteException;
+    public void updatePreferredSetupActivity(ComponentName preferredActivity, int userId)
+            throws RemoteException;
 
     public int getPackageProcessState(String packageName) throws RemoteException;
 
@@ -839,4 +841,5 @@
     int GET_PACKAGE_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+293;
     int SHOW_LOCK_TASK_ESCAPE_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+294;
     int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295;
+    int UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296;
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 47133d4..ed814c3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4325,4 +4325,21 @@
             }
         }
     }
+
+    /**
+     * Called by a device initializer to set the activity to be launched on device boot or after a
+     * user switch during user setup. This activity will be started regardless of the priority of
+     * other 'home' activities. Once user setup is complete, the preferred setup activity will be
+     * ignored.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param activity The Activity to be started by default during user setup.
+     */
+    public void setPreferredSetupActivity(ComponentName admin, ComponentName activity) {
+        try {
+            mService.setPreferredSetupActivity(admin, activity);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Failed talking with device policy service", re);
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 087fc88..a678c51 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -216,6 +216,8 @@
     String getDeviceInitializer();
     ComponentName getDeviceInitializerComponent();
 
+    void setPreferredSetupActivity(in ComponentName admin, in ComponentName activity);
+
     void setUserIcon(in ComponentName admin, in Bitmap icon);
 
     void sendDeviceInitializerStatus(int statusCode, String description);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d851ad7..eeac69a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -38,6 +38,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.SystemClock;
 import android.os.ServiceManager;
 import android.provider.Settings;
@@ -64,6 +65,16 @@
     private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
 
     /**
+     * System properties for whether the default microphone and speaker paths support
+     * near-ultrasound frequencies (range of 18 - 21 kHz).
+     */
+    private static final String SYSTEM_PROPERTY_MIC_NEAR_ULTRASOUND =
+            "persist.audio.mic.ultrasound";
+    private static final String SYSTEM_PROPERTY_SPEAKER_NEAR_ULTRASOUND =
+            "persist.audio.spkr.ultrasound";
+    private static final String DEFAULT_RESULT_FALSE_STRING = "false";
+
+    /**
      * Broadcast intent, a hint for applications that audio is about to become
      * 'noisy' due to a change in audio outputs. For example, this intent may
      * be sent when a wired headset is unplugged, or when an A2DP audio
@@ -3175,6 +3186,12 @@
         } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
             int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
             return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
+        } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
+            return SystemProperties.get(SYSTEM_PROPERTY_MIC_NEAR_ULTRASOUND,
+                    DEFAULT_RESULT_FALSE_STRING);
+        } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
+            return SystemProperties.get(SYSTEM_PROPERTY_SPEAKER_NEAR_ULTRASOUND,
+                    DEFAULT_RESULT_FALSE_STRING);
         } else {
             // null or unknown key
             return null;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 0d61606..1953e75 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1500,17 +1500,16 @@
         }
 
         public void onPackageRemovedLocked(String packageName, int userId) {
-            final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
-            SettingsState globalSettings = mSettingsStates.get(globalKey);
-            if (globalSettings != null) globalSettings.onPackageRemovedLocked(packageName);
-
-            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
-            SettingsState secureSettings = mSettingsStates.get(secureKey);
-            if (secureSettings != null) secureSettings.onPackageRemovedLocked(packageName);
+            // Global and secure settings are signature protected. Apps signed
+            // by the platform certificate are generally not uninstalled  and
+            // the main exception is tests. We trust components signed
+            // by the platform certificate and do not do a clean up after them.
 
             final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
             SettingsState systemSettings = mSettingsStates.get(systemKey);
-            if (systemSettings != null) systemSettings.onPackageRemovedLocked(packageName);
+            if (systemSettings != null) {
+                systemSettings.onPackageRemovedLocked(packageName);
+            }
         }
 
         private SettingsState peekSettingsStateLocked(int key) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 8d99a64..f853f3f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -153,7 +153,7 @@
         final int settingCount = mSettings.size();
         for (int i = settingCount - 1; i >= 0; i--) {
             String name = mSettings.keyAt(i);
-            // Settings defined by use are never dropped.
+            // Settings defined by us are never dropped.
             if (Settings.System.PUBLIC_SETTINGS.contains(name)
                     || Settings.System.PRIVATE_SETTINGS.contains(name)) {
                 continue;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4970e0f..15d7367 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -442,6 +442,12 @@
      */
     String mDeviceOwnerName;
 
+    /**
+     * Preferred activities to start on boot/user switch, as set by DevicePolicyManager. Indexed
+     * by userId.
+     */
+    SparseArray<ComponentName> mPreferredSetupActivities = new SparseArray<>();
+
     public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
         public final Bundle extras;
@@ -3334,15 +3340,22 @@
         ComponentName comp = intent.getComponent();
         try {
             if (comp != null) {
+                // Factory test.
                 ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
             } else {
-                ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
-                        intent,
-                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                            flags, userId);
+                ComponentName preferredComponent = mPreferredSetupActivities.get(userId);
+                if (preferredComponent != null) {
+                    ai = AppGlobals.getPackageManager().getActivityInfo(
+                            preferredComponent, flags, userId);
+                } else {
+                    ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
+                            intent,
+                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                                flags, userId);
 
-                if (info != null) {
-                    ai = info.activityInfo;
+                    if (info != null) {
+                        ai = info.activityInfo;
+                    }
                 }
             }
         } catch (RemoteException e) {
@@ -8574,6 +8587,22 @@
     }
 
     @Override
+    public void updatePreferredSetupActivity(ComponentName preferredActivity, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+            throw new SecurityException(
+                    "updatePreferredSetupActivity called from non-system process");
+        }
+        synchronized (this) {
+            if (preferredActivity == null) {
+                mPreferredSetupActivities.delete(userId);
+            } else {
+                mPreferredSetupActivities.put(userId, preferredActivity);
+            }
+        }
+    }
+
+    @Override
     public void updateDeviceOwner(String packageName) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2b88158..31d7f74 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -181,6 +181,7 @@
 
     private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
     private static final String ATTR_SETUP_COMPLETE = "setup-complete";
+    private static final String ATTR_PREFERRED_SETUP_ACTIVITY = "setup-activity";
 
     private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
 
@@ -315,6 +316,8 @@
 
         boolean doNotAskCredentialsOnBoot = false;
 
+        ComponentName mPreferredSetupActivity;
+
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
@@ -1410,7 +1413,12 @@
                 out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER,
                         policy.mDelegatedCertInstallerPackage);
             }
-
+            if (policy.mPreferredSetupActivity != null) {
+                out.attribute(null, ATTR_PREFERRED_SETUP_ACTIVITY,
+                        policy.mPreferredSetupActivity.flattenToString());
+            } else {
+                out.attribute(null, ATTR_PREFERRED_SETUP_ACTIVITY, "");
+            }
 
             final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
@@ -1531,6 +1539,12 @@
             }
             policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null,
                     ATTR_DELEGATED_CERT_INSTALLER);
+            String preferredSetupActivity =
+                    parser.getAttributeValue(null, ATTR_PREFERRED_SETUP_ACTIVITY);
+            if (preferredSetupActivity != null) {
+                policy.mPreferredSetupActivity =
+                        ComponentName.unflattenFromString(preferredSetupActivity);
+            }
 
             type = parser.next();
             int outerDepth = parser.getDepth();
@@ -1654,6 +1668,7 @@
         if (!policy.mStatusBarEnabledState) {
             setStatusBarEnabledStateInternal(policy.mStatusBarEnabledState, userHandle);
         }
+        updatePreferredSetupActivityLocked(userHandle);
     }
 
     private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
@@ -4632,6 +4647,43 @@
     }
 
     @Override
+    public void setPreferredSetupActivity(ComponentName who, ComponentName activity) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin activeAdmin =
+                    getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (!isDeviceInitializer(activeAdmin.info.getPackageName())) {
+                throw new SecurityException(
+                        "This method can only be called by device initializers");
+            }
+            int userHandle = UserHandle.getCallingUserId();
+            DevicePolicyData userData = getUserData(userHandle);
+            userData.mPreferredSetupActivity = activity;
+            saveSettingsLocked(userHandle);
+            updatePreferredSetupActivityLocked(userHandle);
+        }
+    }
+
+    private void updatePreferredSetupActivityLocked(int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
+        IActivityManager am = ActivityManagerNative.getDefault();
+        long ident = Binder.clearCallingIdentity();
+        try {
+            am.updatePreferredSetupActivity(
+                    getUserData(userHandle).mPreferredSetupActivity, userHandle);
+        } catch (RemoteException e) {
+            // Not gonna happen.
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
@@ -6000,6 +6052,9 @@
                 if (!policy.mUserSetupComplete) {
                     policy.mUserSetupComplete = true;
                     synchronized (this) {
+                        // Clear the preferred setup activity.
+                        policy.mPreferredSetupActivity = null;
+                        updatePreferredSetupActivityLocked(userHandle);
                         // The DeviceInitializer was whitelisted but now should be removed.
                         removeDeviceInitializerFromLockTaskPackages(userHandle);
                         saveSettingsLocked(userHandle);