Merge "Allow badging updates to install sessions." into lmp-dev

This commit is contained in:
Jeff Sharkey
2014-09-05 17:56:38 +00:00
committed by Android (Google) Code Review
7 changed files with 135 additions and 91 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {