Merge "Sending explicit broadcast to the launcher when a package is installed"
diff --git a/api/current.txt b/api/current.txt
index 3710b29..221c55b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10166,9 +10166,11 @@
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10211,6 +10213,7 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
diff --git a/api/system-current.txt b/api/system-current.txt
index 4f89f0c..51e35dd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10703,9 +10703,11 @@
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10748,6 +10750,7 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
diff --git a/api/test-current.txt b/api/test-current.txt
index a33bb8f..befc97f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10198,9 +10198,11 @@
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10243,6 +10245,7 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 1aef363..91520f1 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -547,6 +547,12 @@
throw new IllegalArgumentException("Missing inherit package name");
}
break;
+ case "--pkg":
+ sessionParams.appPackageName = nextOptionData();
+ if (sessionParams.appPackageName == null) {
+ throw new IllegalArgumentException("Missing package name");
+ }
+ break;
case "-S":
final long sizeBytes = Long.parseLong(nextOptionData());
if (sizeBytes <= 0) {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 278a6d0..9d04cc9 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -95,6 +95,18 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ /**
+ * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
+ * for a new install is committed. For managed profile, this is sent to the default launcher
+ * of the primary profile.
+ * <p>
+ * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
+ * session was created in {@link Intent#EXTRA_USER}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SESSION_COMMITTED =
+ "android.content.pm.action.SESSION_COMMITTED";
+
/** {@hide} */
public static final String
ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
@@ -107,6 +119,13 @@
public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
/**
+ * {@link SessionInfo} that an operation is working with.
+ *
+ * @see Intent#getParcelableExtra(String)
+ */
+ public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
+
+ /**
* Package name that an operation is working with.
*
* @see Intent#getStringExtra(String)
@@ -1184,6 +1203,8 @@
/** {@hide} */
public int mode;
/** {@hide} */
+ public int installReason;
+ /** {@hide} */
public long sizeBytes;
/** {@hide} */
public String appPackageName;
@@ -1206,6 +1227,7 @@
active = source.readInt() != 0;
mode = source.readInt();
+ installReason = source.readInt();
sizeBytes = source.readLong();
appPackageName = source.readString();
appIcon = source.readParcelable(null);
@@ -1256,6 +1278,15 @@
return active;
}
+ /**
+ * Return the reason for installing this package.
+ *
+ * @see PackageManager#INSTALL_REASON_UNKNOWN
+ */
+ public int getInstallReason() {
+ return installReason;
+ }
+
/** {@hide} */
@Deprecated
public boolean isOpen() {
@@ -1324,6 +1355,7 @@
dest.writeInt(active ? 1 : 0);
dest.writeInt(mode);
+ dest.writeInt(installReason);
dest.writeLong(sizeBytes);
dest.writeString(appPackageName);
dest.writeParcelable(appIcon, flags);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 054fad2..54d7249 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -522,6 +522,8 @@
<protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1c5675a..fd731c3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,6 +29,7 @@
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -45,6 +46,7 @@
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileBridge;
@@ -295,6 +297,7 @@
info.active = mActiveCount.get() > 0;
info.mode = params.mode;
+ info.installReason = params.installReason;
info.sizeBytes = params.sizeBytes;
info.appPackageName = params.appPackageName;
info.appIcon = params.appIcon;
@@ -1139,6 +1142,25 @@
}
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
+
+ // Send broadcast to default launcher only if it's a new install
+ final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
+ if (success && isNewInstall) {
+ UserManagerService ums = UserManagerService.getInstance();
+ if (ums != null) {
+ final UserInfo parent = ums.getProfileParent(userId);
+ final int launcherUid = (parent != null) ? parent.id : userId;
+ final ComponentName launcherComponent = mPm.getDefaultHomeActivity(launcherUid);
+ if (launcherComponent != null) {
+ Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, generateInfo())
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+ .setPackage(launcherComponent.getPackageName());
+ mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
+ }
+ }
+ }
+
mCallback.onSessionFinished(this, success);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5ebced8..06f8077 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19645,6 +19645,35 @@
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
+ /**
+ * Report the 'Home' activity which is currently set as "always use this one". If non is set
+ * then reports the most likely home activity or null if there are more than one.
+ */
+ public ComponentName getDefaultHomeActivity(int userId) {
+ List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+ ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
+ if (cn != null) {
+ return cn;
+ }
+
+ // Find the launcher with the highest priority and return that component if there are no
+ // other home activity with the same priority.
+ int lastPriority = Integer.MIN_VALUE;
+ ComponentName lastComponent = null;
+ final int size = allHomeCandidates.size();
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo ri = allHomeCandidates.get(i);
+ if (ri.priority > lastPriority) {
+ lastComponent = ri.activityInfo.getComponentName();
+ lastPriority = ri.priority;
+ } else if (ri.priority == lastPriority) {
+ // Two components found with same priority.
+ lastComponent = null;
+ }
+ }
+ return lastComponent;
+ }
+
private Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);