Merge "Allow badging updates to install sessions." into lmp-dev
This commit is contained in:
@ -8681,15 +8681,17 @@ package android.content.pm {
|
||||
|
||||
public class PackageInstaller {
|
||||
method public void abandonSession(int);
|
||||
method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
|
||||
method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
|
||||
method public int createSession(android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
|
||||
method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
|
||||
method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
|
||||
method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
|
||||
method public android.content.pm.PackageInstaller.Session openSession(int);
|
||||
method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
|
||||
method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
|
||||
method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
|
||||
method public void uninstall(java.lang.String, android.content.IntentSender);
|
||||
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_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";
|
||||
@ -8721,6 +8723,7 @@ package android.content.pm {
|
||||
|
||||
public static abstract class PackageInstaller.SessionCallback {
|
||||
ctor public PackageInstaller.SessionCallback();
|
||||
method public abstract void onBadgingChanged(int);
|
||||
method public abstract void onClosed(int);
|
||||
method public abstract void onCreated(int);
|
||||
method public abstract void onFinished(int, boolean);
|
||||
|
@ -22,14 +22,21 @@ import android.content.pm.IPackageInstallerSession;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.IntentSender;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
/** {@hide} */
|
||||
interface IPackageInstaller {
|
||||
int createSession(in PackageInstaller.SessionParams params, String installerPackageName, int userId);
|
||||
|
||||
void updateSessionAppIcon(int sessionId, in Bitmap appIcon);
|
||||
void updateSessionAppLabel(int sessionId, String appLabel);
|
||||
|
||||
void abandonSession(int sessionId);
|
||||
|
||||
IPackageInstallerSession openSession(int sessionId);
|
||||
|
||||
PackageInstaller.SessionInfo getSessionInfo(int sessionId);
|
||||
|
||||
List<PackageInstaller.SessionInfo> getAllSessions(int userId);
|
||||
List<PackageInstaller.SessionInfo> getMySessions(String installerPackageName, int userId);
|
||||
|
||||
|
@ -19,6 +19,7 @@ package android.content.pm;
|
||||
/** {@hide} */
|
||||
oneway interface IPackageInstallerCallback {
|
||||
void onSessionCreated(int sessionId);
|
||||
void onSessionBadgingChanged(int sessionId);
|
||||
void onSessionOpened(int sessionId);
|
||||
void onSessionProgressChanged(int sessionId, float progress);
|
||||
void onSessionClosed(int sessionId);
|
||||
|
@ -312,6 +312,32 @@ public class PackageInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the icon representing the app being installed in a specific
|
||||
* session. This should be roughly
|
||||
* {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
|
||||
*/
|
||||
public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
|
||||
try {
|
||||
mInstaller.updateSessionAppIcon(sessionId, appIcon);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the label representing the app being installed in a specific
|
||||
* session.
|
||||
*/
|
||||
public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
|
||||
try {
|
||||
final String val = (appLabel != null) ? appLabel.toString() : null;
|
||||
mInstaller.updateSessionAppLabel(sessionId, val);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void abandonSession(int sessionId) {
|
||||
try {
|
||||
mInstaller.abandonSession(sessionId);
|
||||
@ -321,8 +347,7 @@ public class PackageInstaller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return details for a specific session. To succeed, the caller must either
|
||||
* own this session, or be the current home app.
|
||||
* Return details for a specific session.
|
||||
*/
|
||||
public @Nullable SessionInfo getSessionInfo(int sessionId) {
|
||||
try {
|
||||
@ -334,7 +359,6 @@ public class PackageInstaller {
|
||||
|
||||
/**
|
||||
* Return list of all active install sessions, regardless of the installer.
|
||||
* To succeed, the caller must be the current home app.
|
||||
*/
|
||||
public @NonNull List<SessionInfo> getAllSessions() {
|
||||
final ApplicationInfo info = mContext.getApplicationInfo();
|
||||
@ -405,6 +429,12 @@ public class PackageInstaller {
|
||||
*/
|
||||
public abstract void onCreated(int sessionId);
|
||||
|
||||
/**
|
||||
* Badging details for an existing session has changed. For example, the
|
||||
* app icon or label has been updated.
|
||||
*/
|
||||
public abstract void onBadgingChanged(int sessionId);
|
||||
|
||||
/**
|
||||
* Session has been opened. A session is usually opened when the
|
||||
* installer is actively writing data.
|
||||
@ -436,10 +466,11 @@ public class PackageInstaller {
|
||||
private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
|
||||
Handler.Callback {
|
||||
private static final int MSG_SESSION_CREATED = 1;
|
||||
private static final int MSG_SESSION_OPENED = 2;
|
||||
private static final int MSG_SESSION_PROGRESS_CHANGED = 3;
|
||||
private static final int MSG_SESSION_CLOSED = 4;
|
||||
private static final int MSG_SESSION_FINISHED = 5;
|
||||
private static final int MSG_SESSION_BADGING_CHANGED = 2;
|
||||
private static final int MSG_SESSION_OPENED = 3;
|
||||
private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
|
||||
private static final int MSG_SESSION_CLOSED = 5;
|
||||
private static final int MSG_SESSION_FINISHED = 6;
|
||||
|
||||
final SessionCallback mCallback;
|
||||
final Handler mHandler;
|
||||
@ -455,6 +486,9 @@ public class PackageInstaller {
|
||||
case MSG_SESSION_CREATED:
|
||||
mCallback.onCreated(msg.arg1);
|
||||
return true;
|
||||
case MSG_SESSION_BADGING_CHANGED:
|
||||
mCallback.onBadgingChanged(msg.arg1);
|
||||
return true;
|
||||
case MSG_SESSION_OPENED:
|
||||
mCallback.onOpened(msg.arg1);
|
||||
return true;
|
||||
@ -476,6 +510,11 @@ public class PackageInstaller {
|
||||
mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionBadgingChanged(int sessionId) {
|
||||
mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionOpened(int sessionId) {
|
||||
mHandler.obtainMessage(MSG_SESSION_OPENED, sessionId, 0).sendToTarget();
|
||||
@ -499,22 +538,32 @@ public class PackageInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register to watch for session lifecycle events. To succeed, the caller
|
||||
* must be the current home app.
|
||||
*/
|
||||
/** {@hide} */
|
||||
@Deprecated
|
||||
public void addSessionCallback(@NonNull SessionCallback callback) {
|
||||
addSessionCallback(callback, new Handler());
|
||||
registerSessionCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register to watch for session lifecycle events. To succeed, the caller
|
||||
* must be the current home app.
|
||||
* Register to watch for session lifecycle events.
|
||||
*/
|
||||
public void registerSessionCallback(@NonNull SessionCallback callback) {
|
||||
registerSessionCallback(callback, new Handler());
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@Deprecated
|
||||
public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
|
||||
registerSessionCallback(callback, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register to watch for session lifecycle events.
|
||||
*
|
||||
* @param handler to dispatch callback events through, otherwise uses
|
||||
* calling thread.
|
||||
*/
|
||||
public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
|
||||
public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
|
||||
// TODO: remove this temporary guard once we have new prebuilts
|
||||
final ApplicationInfo info = mContext.getApplicationInfo();
|
||||
if ("com.google.android.googlequicksearchbox".equals(info.packageName)
|
||||
@ -535,10 +584,16 @@ public class PackageInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@Deprecated
|
||||
public void removeSessionCallback(@NonNull SessionCallback callback) {
|
||||
unregisterSessionCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an existing callback.
|
||||
*/
|
||||
public void removeSessionCallback(@NonNull SessionCallback callback) {
|
||||
public void unregisterSessionCallback(@NonNull SessionCallback callback) {
|
||||
synchronized (mDelegates) {
|
||||
for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
|
||||
final SessionCallbackDelegate delegate = i.next();
|
||||
|
@ -47,12 +47,12 @@ import android.content.pm.IPackageInstaller;
|
||||
import android.content.pm.IPackageInstallerCallback;
|
||||
import android.content.pm.IPackageInstallerSession;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageInstaller.SessionInfo;
|
||||
import android.content.pm.PackageInstaller.SessionParams;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.PackageLite;
|
||||
import android.content.pm.PackageParser.PackageParserException;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
@ -580,6 +580,30 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
|
||||
synchronized (mSessions) {
|
||||
final PackageInstallerSession session = mSessions.get(sessionId);
|
||||
if (session == null || !isCallingUidOwner(session)) {
|
||||
throw new SecurityException("Caller has no access to session " + sessionId);
|
||||
}
|
||||
session.params.appIcon = appIcon;
|
||||
mInternalCallback.onSessionBadgingChanged(session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSessionAppLabel(int sessionId, String appLabel) {
|
||||
synchronized (mSessions) {
|
||||
final PackageInstallerSession session = mSessions.get(sessionId);
|
||||
if (session == null || !isCallingUidOwner(session)) {
|
||||
throw new SecurityException("Caller has no access to session " + sessionId);
|
||||
}
|
||||
session.params.appLabel = appLabel;
|
||||
mInternalCallback.onSessionBadgingChanged(session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abandonSession(int sessionId) {
|
||||
synchronized (mSessions) {
|
||||
@ -681,9 +705,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
public SessionInfo getSessionInfo(int sessionId) {
|
||||
synchronized (mSessions) {
|
||||
final PackageInstallerSession session = mSessions.get(sessionId);
|
||||
if (!isCallingUidOwner(session)) {
|
||||
enforceCallerCanReadSessions();
|
||||
}
|
||||
return session != null ? session.generateInfo() : null;
|
||||
}
|
||||
}
|
||||
@ -691,7 +712,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
@Override
|
||||
public List<SessionInfo> getAllSessions(int userId) {
|
||||
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions");
|
||||
enforceCallerCanReadSessions();
|
||||
|
||||
final List<SessionInfo> result = new ArrayList<>();
|
||||
synchronized (mSessions) {
|
||||
@ -755,8 +775,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
@Override
|
||||
public void registerCallback(IPackageInstallerCallback callback, int userId) {
|
||||
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback");
|
||||
enforceCallerCanReadSessions();
|
||||
|
||||
mCallbacks.register(callback, userId);
|
||||
}
|
||||
|
||||
@ -787,21 +805,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We allow those with permission, or the current home app.
|
||||
*/
|
||||
private void enforceCallerCanReadSessions() {
|
||||
final boolean hasPermission = (mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.READ_INSTALL_SESSIONS)
|
||||
== PackageManager.PERMISSION_GRANTED);
|
||||
final boolean isHomeApp = mPm.checkCallerIsHomeApp();
|
||||
if (hasPermission || isHomeApp) {
|
||||
return;
|
||||
} else {
|
||||
throw new SecurityException("Caller must be current home app to read install sessions");
|
||||
}
|
||||
}
|
||||
|
||||
static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
|
||||
private final Context mContext;
|
||||
private final IntentSender mTarget;
|
||||
@ -893,10 +896,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
|
||||
private static class Callbacks extends Handler {
|
||||
private static final int MSG_SESSION_CREATED = 1;
|
||||
private static final int MSG_SESSION_OPENED = 2;
|
||||
private static final int MSG_SESSION_PROGRESS_CHANGED = 3;
|
||||
private static final int MSG_SESSION_CLOSED = 4;
|
||||
private static final int MSG_SESSION_FINISHED = 5;
|
||||
private static final int MSG_SESSION_BADGING_CHANGED = 2;
|
||||
private static final int MSG_SESSION_OPENED = 3;
|
||||
private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
|
||||
private static final int MSG_SESSION_CLOSED = 5;
|
||||
private static final int MSG_SESSION_FINISHED = 6;
|
||||
|
||||
private final RemoteCallbackList<IPackageInstallerCallback>
|
||||
mCallbacks = new RemoteCallbackList<>();
|
||||
@ -938,6 +942,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
case MSG_SESSION_CREATED:
|
||||
callback.onSessionCreated(sessionId);
|
||||
break;
|
||||
case MSG_SESSION_BADGING_CHANGED:
|
||||
callback.onSessionBadgingChanged(sessionId);
|
||||
break;
|
||||
case MSG_SESSION_OPENED:
|
||||
callback.onSessionOpened(sessionId);
|
||||
break;
|
||||
@ -957,6 +964,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
|
||||
}
|
||||
|
||||
private void notifySessionBadgingChanged(int sessionId, int userId) {
|
||||
obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
|
||||
}
|
||||
|
||||
private void notifySessionOpened(int sessionId, int userId) {
|
||||
obtainMessage(MSG_SESSION_OPENED, sessionId, userId).sendToTarget();
|
||||
}
|
||||
@ -1006,14 +1017,19 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
}
|
||||
|
||||
class InternalCallback {
|
||||
public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
|
||||
mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
|
||||
public void onSessionBadgingChanged(PackageInstallerSession session) {
|
||||
mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
|
||||
writeSessionsAsync();
|
||||
}
|
||||
|
||||
public void onSessionOpened(PackageInstallerSession session) {
|
||||
mCallbacks.notifySessionOpened(session.sessionId, session.userId);
|
||||
}
|
||||
|
||||
public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
|
||||
mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
|
||||
}
|
||||
|
||||
public void onSessionClosed(PackageInstallerSession session) {
|
||||
mCallbacks.notifySessionClosed(session.sessionId, session.userId);
|
||||
}
|
||||
|
@ -294,7 +294,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
private void computeProgressLocked() {
|
||||
mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f);
|
||||
if (mProgress <= 0.8f) {
|
||||
mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
private void maybePublishProgress() {
|
||||
@ -485,7 +487,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
// TODO: surface more granular state from dexopt
|
||||
mCallback.onSessionProgressChanged(this, 0.9f);
|
||||
mProgress = 0.9f;
|
||||
maybePublishProgress();
|
||||
|
||||
// Unpack native libraries
|
||||
extractNativeLibraries(mResolvedStageDir, params.abiOverride);
|
||||
|
@ -11746,47 +11746,6 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
preferred.activityInfo.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if calling UID is the current home app. This handles both the case
|
||||
* where the user has selected a specific home app, and where there is only
|
||||
* one home app.
|
||||
*/
|
||||
public boolean checkCallerIsHomeApp() {
|
||||
final Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_HOME);
|
||||
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
final List<ResolveInfo> allHomes = queryIntentActivities(intent, null, 0, callingUserId);
|
||||
final ResolveInfo preferredHome = findPreferredActivity(intent, null, 0, allHomes, 0, true,
|
||||
false, false, callingUserId);
|
||||
|
||||
if (preferredHome != null) {
|
||||
if (callingUid == preferredHome.activityInfo.applicationInfo.uid) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (ResolveInfo info : allHomes) {
|
||||
if (callingUid == info.activityInfo.applicationInfo.uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce that calling UID is the current home app. This handles both the
|
||||
* case where the user has selected a specific home app, and where there is
|
||||
* only one home app.
|
||||
*/
|
||||
public void enforceCallerIsHomeApp() {
|
||||
if (!checkCallerIsHomeApp()) {
|
||||
throw new SecurityException("Caller is not currently selected home app");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEnabledSetting(String appPackageName,
|
||||
int newState, int flags, int userId, String callingPackage) {
|
||||
|
Reference in New Issue
Block a user