Implementing a package install progress listener for L
issue: 15835307 Change-Id: I71aaea087963f2e0e1206447190cbe23c174057d
This commit is contained in:
@@ -434,65 +434,48 @@ public class BubbleTextView extends TextView {
|
||||
}
|
||||
|
||||
public void applyState() {
|
||||
final int progressLevel;
|
||||
final int state = getState();
|
||||
if (DEBUG) Log.d(TAG, "applying icon state: " + state);
|
||||
if (getTag() instanceof ShortcutInfo) {
|
||||
ShortcutInfo info = (ShortcutInfo) getTag();
|
||||
final int state = info.getState();
|
||||
|
||||
switch(state) {
|
||||
case ShortcutInfo.PACKAGE_STATE_DEFAULT:
|
||||
super.setText(mDefaultText);
|
||||
progressLevel = 100;
|
||||
break;
|
||||
final int progressLevel;
|
||||
if (DEBUG) Log.d(TAG, "applying icon state: " + state);
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_ENQUEUED:
|
||||
setText(R.string.package_state_enqueued);
|
||||
progressLevel = 0;
|
||||
break;
|
||||
switch(state) {
|
||||
case ShortcutInfo.PACKAGE_STATE_DEFAULT:
|
||||
progressLevel = 100;
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_DOWNLOADING:
|
||||
setText(R.string.package_state_downloading);
|
||||
// TODO(sunnygoyal): fix progress
|
||||
progressLevel = 30;
|
||||
break;
|
||||
case ShortcutInfo.PACKAGE_STATE_INSTALLING:
|
||||
setText(R.string.package_state_installing);
|
||||
progressLevel = info.getProgress();
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_INSTALLING:
|
||||
setText(R.string.package_state_installing);
|
||||
progressLevel = 100;
|
||||
break;
|
||||
case ShortcutInfo.PACKAGE_STATE_ERROR:
|
||||
case ShortcutInfo.PACKAGE_STATE_UNKNOWN:
|
||||
default:
|
||||
progressLevel = 0;
|
||||
setText(R.string.package_state_unknown);
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_ERROR:
|
||||
setText(R.string.package_state_error);
|
||||
progressLevel = 0;
|
||||
break;
|
||||
Drawable[] drawables = getCompoundDrawables();
|
||||
Drawable top = drawables[1];
|
||||
if (top != null) {
|
||||
final PreloadIconDrawable preloadDrawable;
|
||||
if (top instanceof PreloadIconDrawable) {
|
||||
preloadDrawable = (PreloadIconDrawable) top;
|
||||
} else {
|
||||
preloadDrawable = new PreloadIconDrawable(top, getResources());
|
||||
setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
|
||||
}
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_UNKNOWN:
|
||||
default:
|
||||
progressLevel = 0;
|
||||
setText(R.string.package_state_unknown);
|
||||
break;
|
||||
}
|
||||
preloadDrawable.setLevel(progressLevel);
|
||||
if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
|
||||
preloadDrawable.maybePerformFinishedAnimation();
|
||||
}
|
||||
|
||||
Drawable[] drawables = getCompoundDrawables();
|
||||
Drawable top = drawables[1];
|
||||
if ((top != null) && !(top instanceof PreloadIconDrawable)) {
|
||||
top = new PreloadIconDrawable(top, getResources());
|
||||
setCompoundDrawables(drawables[0], top, drawables[2], drawables[3]);
|
||||
}
|
||||
if (top != null) {
|
||||
top.setLevel(progressLevel);
|
||||
if ((top instanceof PreloadIconDrawable)
|
||||
&& (state == ShortcutInfo.PACKAGE_STATE_DEFAULT)) {
|
||||
((PreloadIconDrawable) top).maybePerformFinishedAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getState() {
|
||||
if (! (getTag() instanceof ShortcutInfo)) {
|
||||
return ShortcutInfo.PACKAGE_STATE_DEFAULT;
|
||||
} else {
|
||||
ShortcutInfo info = (ShortcutInfo) getTag();
|
||||
return info.getState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +82,9 @@ import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.Window;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
@@ -93,9 +92,7 @@ import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Advanceable;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -107,10 +104,10 @@ import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.PagedView.PageSwitchListener;
|
||||
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.PagedView.PageSwitchListener;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
@@ -1055,12 +1052,15 @@ public class Launcher extends Activity
|
||||
}
|
||||
mWorkspace.updateInteractionForState();
|
||||
mWorkspace.onResume();
|
||||
|
||||
PackageInstallerCompat.getInstance(this).onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
// Ensure that items added to Launcher are queued until Launcher returns
|
||||
InstallShortcutReceiver.enableInstallQueue();
|
||||
PackageInstallerCompat.getInstance(this).onPause();
|
||||
|
||||
super.onPause();
|
||||
mPaused = true;
|
||||
@@ -2028,6 +2028,7 @@ public class Launcher extends Activity
|
||||
mWorkspace = null;
|
||||
mDragController = null;
|
||||
|
||||
PackageInstallerCompat.getInstance(this).onStop();
|
||||
LauncherAnimUtils.onDestroyActivity();
|
||||
}
|
||||
|
||||
@@ -4478,6 +4479,7 @@ public class Launcher extends Activity
|
||||
mWorkspace.getUniqueComponents(true, null);
|
||||
mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
|
||||
}
|
||||
PackageInstallerCompat.getInstance(this).onFinishBind();
|
||||
}
|
||||
|
||||
private void sendLoadingCompleteBroadcastIfNecessary() {
|
||||
@@ -4591,9 +4593,10 @@ public class Launcher extends Activity
|
||||
*
|
||||
* Implementation of the method from LauncherModel.Callbacks.
|
||||
*/
|
||||
public void updatePackageState(String pkgName, int state) {
|
||||
@Override
|
||||
public void updatePackageState(ArrayList<PackageInstallInfo> installInfo) {
|
||||
if (mWorkspace != null) {
|
||||
mWorkspace.updatePackageState(pkgName, state);
|
||||
mWorkspace.updatePackageState(installInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.*;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
@@ -25,8 +29,10 @@ import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
||||
private static final String TAG = "LauncherAppState";
|
||||
@@ -251,8 +257,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
||||
return getInstance().mBuildInfo.isDogfoodBuild();
|
||||
}
|
||||
|
||||
public void setPackageState(String pkgName, int state) {
|
||||
if (DEBUG) Log.d(TAG, "setPackageState(" + pkgName + ", " + state + ")");
|
||||
mModel.setPackageState(pkgName, state);
|
||||
public void setPackageState(ArrayList<PackageInstallInfo> installInfo) {
|
||||
mModel.setPackageState(installInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import android.util.Pair;
|
||||
import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
|
||||
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
|
||||
@@ -195,7 +196,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
ArrayList<ItemInfo> addAnimated,
|
||||
ArrayList<AppInfo> addedApps);
|
||||
public void bindAppsUpdated(ArrayList<AppInfo> apps);
|
||||
public void updatePackageState(String pkgName, int state);
|
||||
public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);
|
||||
public void bindComponentsRemoved(ArrayList<String> packageNames,
|
||||
ArrayList<AppInfo> appInfos, UserHandleCompat user);
|
||||
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
|
||||
@@ -332,13 +333,13 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setPackageState(final String pkgName, final int state) {
|
||||
public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {
|
||||
// Process the updated package state
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
|
||||
if (callbacks != null) {
|
||||
callbacks.updatePackageState(pkgName, state);
|
||||
callbacks.updatePackageState(installInfo);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,13 +42,7 @@ public class ShortcutInfo extends ItemInfo {
|
||||
public static final int PACKAGE_STATE_DEFAULT = 0;
|
||||
|
||||
/** {@link #mState} meaning some external entity has promised to install this package. */
|
||||
public static final int PACKAGE_STATE_ENQUEUED = 1;
|
||||
|
||||
/** {@link #mState} meaning but some external entity is downloading this package. */
|
||||
public static final int PACKAGE_STATE_DOWNLOADING = 2;
|
||||
|
||||
/** {@link #mState} meaning some external entity is installing this package. */
|
||||
public static final int PACKAGE_STATE_INSTALLING = 3;
|
||||
public static final int PACKAGE_STATE_INSTALLING = 1;
|
||||
|
||||
/**
|
||||
* The intent used to start the application.
|
||||
@@ -89,6 +83,11 @@ public class ShortcutInfo extends ItemInfo {
|
||||
*/
|
||||
protected int mState;
|
||||
|
||||
/**
|
||||
* The installation progress [0-100] of the package that this shortcut represents.
|
||||
*/
|
||||
protected int mProgress;
|
||||
|
||||
long firstInstallTime;
|
||||
int flags = 0;
|
||||
|
||||
@@ -237,16 +236,24 @@ public class ShortcutInfo extends ItemInfo {
|
||||
|
||||
public boolean isAbandoned() {
|
||||
return isPromise()
|
||||
&& (mState == ShortcutInfo.PACKAGE_STATE_ERROR
|
||||
|| mState == ShortcutInfo.PACKAGE_STATE_UNKNOWN);
|
||||
&& (mState == PACKAGE_STATE_ERROR
|
||||
|| mState == PACKAGE_STATE_UNKNOWN);
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
public int getProgress() {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
public void setProgress(int progress) {
|
||||
mProgress = progress;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
mState = state;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ import android.widget.TextView;
|
||||
import com.android.launcher3.FolderIcon.FolderRingAnimator;
|
||||
import com.android.launcher3.Launcher.CustomContentCallbacks;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -4864,26 +4865,32 @@ public class Workspace extends SmoothPagedView
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePackageState(final String pkgName, final int state) {
|
||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v, View parent) {
|
||||
if (info instanceof ShortcutInfo
|
||||
&& ((ShortcutInfo) info).isPromiseFor(pkgName)
|
||||
&& v instanceof BubbleTextView) {
|
||||
((ShortcutInfo) info).setState(state);
|
||||
((BubbleTextView)v).applyState();
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {
|
||||
HashSet<String> completedPackages = new HashSet<>();
|
||||
|
||||
if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
|
||||
// Update any pending widget
|
||||
HashSet<String> packages = new HashSet<String>();
|
||||
packages.add(pkgName);
|
||||
restorePendingWidgets(packages);
|
||||
for (final PackageInstallInfo installInfo : installInfos) {
|
||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v, View parent) {
|
||||
if (info instanceof ShortcutInfo
|
||||
&& ((ShortcutInfo) info).isPromiseFor(installInfo.packageName)
|
||||
&& v instanceof BubbleTextView) {
|
||||
((ShortcutInfo) info).setProgress(installInfo.progress);
|
||||
((ShortcutInfo) info).setState(installInfo.state);
|
||||
((BubbleTextView)v).applyState();
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (installInfo.state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
|
||||
completedPackages.add(installInfo.packageName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!completedPackages.isEmpty()) {
|
||||
restorePendingWidgets(completedPackages);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,10 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class LauncherAppsCompat {
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.compat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
public abstract class PackageInstallerCompat {
|
||||
|
||||
private static final Object sInstanceLock = new Object();
|
||||
private static PackageInstallerCompat sInstance;
|
||||
|
||||
public static PackageInstallerCompat getInstance(Context context) {
|
||||
synchronized (sInstanceLock) {
|
||||
if (sInstance == null) {
|
||||
if (Utilities.isLmp()) {
|
||||
sInstance = new PackageInstallerCompatVL(context);
|
||||
} else {
|
||||
sInstance = new PackageInstallerCompatV16(context) { };
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onPause();
|
||||
|
||||
public abstract void onResume();
|
||||
|
||||
public abstract void onFinishBind();
|
||||
|
||||
public abstract void onStop();
|
||||
|
||||
public abstract void recordPackageUpdate(String packageName, int state, int progress);
|
||||
|
||||
public static final class PackageInstallInfo {
|
||||
public final String packageName;
|
||||
|
||||
public int state;
|
||||
public int progress;
|
||||
|
||||
public PackageInstallInfo(String packageName) {
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public PackageInstallInfo(String packageName, int state, int progress) {
|
||||
this.packageName = packageName;
|
||||
this.state = state;
|
||||
this.progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.compat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONStringer;
|
||||
import org.json.JSONTokener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PackageInstallerCompatV16 extends PackageInstallerCompat {
|
||||
|
||||
private static final String TAG = "PackageInstallerCompatV16";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final String KEY_PROGRESS = "progress";
|
||||
private static final String KEY_STATE = "state";
|
||||
|
||||
private static final String PREFS =
|
||||
"com.android.launcher3.compat.PackageInstallerCompatV16.queue";
|
||||
|
||||
protected final SharedPreferences mPrefs;
|
||||
|
||||
boolean mUseQueue;
|
||||
boolean mFinishedBind;
|
||||
boolean mReplayPending;
|
||||
|
||||
PackageInstallerCompatV16(Context context) {
|
||||
mPrefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mUseQueue = true;
|
||||
if (DEBUG) Log.d(TAG, "updates paused");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
mUseQueue = false;
|
||||
if (mFinishedBind) {
|
||||
replayUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishBind() {
|
||||
mFinishedBind = true;
|
||||
if (!mUseQueue) {
|
||||
replayUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() { }
|
||||
|
||||
private void replayUpdates() {
|
||||
if (DEBUG) Log.d(TAG, "updates resumed");
|
||||
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
|
||||
if (app == null) {
|
||||
mReplayPending = true; // try again later
|
||||
if (DEBUG) Log.d(TAG, "app is null, delaying send");
|
||||
return;
|
||||
}
|
||||
mReplayPending = false;
|
||||
ArrayList<PackageInstallInfo> updates = new ArrayList<>();
|
||||
for (String packageName: mPrefs.getAll().keySet()) {
|
||||
final String json = mPrefs.getString(packageName, null);
|
||||
if (!TextUtils.isEmpty(json)) {
|
||||
updates.add(infoFromJson(packageName, json));
|
||||
}
|
||||
}
|
||||
if (!updates.isEmpty()) {
|
||||
sendUpdate(app, updates);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be called by the implementations to register a package update.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void recordPackageUpdate(String packageName, int state, int progress) {
|
||||
SharedPreferences.Editor editor = mPrefs.edit();
|
||||
PackageInstallInfo installInfo = new PackageInstallInfo(packageName);
|
||||
installInfo.progress = progress;
|
||||
installInfo.state = state;
|
||||
if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
|
||||
// no longer necessary to track this package
|
||||
editor.remove(packageName);
|
||||
if (DEBUG) Log.d(TAG, "no longer tracking " + packageName);
|
||||
} else {
|
||||
editor.putString(packageName, infoToJson(installInfo));
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "saved state: " + infoToJson(installInfo)
|
||||
+ " for package: " + packageName);
|
||||
|
||||
}
|
||||
editor.commit();
|
||||
|
||||
if (!mUseQueue) {
|
||||
if (mReplayPending) {
|
||||
replayUpdates();
|
||||
} else {
|
||||
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
|
||||
ArrayList<PackageInstallInfo> update = new ArrayList<>();
|
||||
update.add(installInfo);
|
||||
sendUpdate(app, update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUpdate(LauncherAppState app, ArrayList<PackageInstallInfo> updates) {
|
||||
if (app == null) {
|
||||
mReplayPending = true; // try again later
|
||||
if (DEBUG) Log.d(TAG, "app is null, delaying send");
|
||||
} else {
|
||||
app.setPackageState(updates);
|
||||
}
|
||||
}
|
||||
|
||||
private static PackageInstallInfo infoFromJson(String packageName, String json) {
|
||||
PackageInstallInfo info = new PackageInstallInfo(packageName);
|
||||
try {
|
||||
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
|
||||
info.state = object.getInt(KEY_STATE);
|
||||
info.progress = object.getInt(KEY_PROGRESS);
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "failed to deserialize app state update", e);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private static String infoToJson(PackageInstallInfo info) {
|
||||
String value = null;
|
||||
try {
|
||||
JSONStringer json = new JSONStringer()
|
||||
.object()
|
||||
.key(KEY_STATE).value(info.state)
|
||||
.key(KEY_PROGRESS).value(info.progress)
|
||||
.endObject();
|
||||
value = json.toString();
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "failed to serialize app state update", e);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.compat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.InstallSessionInfo;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageInstaller.SessionCallback;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
|
||||
private static final String TAG = "PackageInstallerCompatVL";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final SparseArray<InstallSessionInfo> mPendingReplays = new SparseArray<>();
|
||||
private final PackageInstaller mInstaller;
|
||||
|
||||
private boolean mResumed;
|
||||
private boolean mBound;
|
||||
|
||||
PackageInstallerCompatVL(Context context) {
|
||||
mInstaller = context.getPackageManager().getPackageInstaller();
|
||||
|
||||
mResumed = false;
|
||||
mBound = false;
|
||||
|
||||
mInstaller.addSessionCallback(mCallback);
|
||||
// On start, send updates for all active sessions
|
||||
for (InstallSessionInfo info : mInstaller.getAllSessions()) {
|
||||
mPendingReplays.append(info.getSessionId(), info);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mInstaller.removeSessionCallback(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishBind() {
|
||||
mBound = true;
|
||||
replayUpdates(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mResumed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
mResumed = true;
|
||||
replayUpdates(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordPackageUpdate(String packageName, int state, int progress) {
|
||||
// No op
|
||||
}
|
||||
|
||||
private void replayUpdates(PackageInstallInfo newInfo) {
|
||||
if (DEBUG) Log.d(TAG, "updates resumed");
|
||||
if (!mResumed || !mBound) {
|
||||
// Not yet ready
|
||||
return;
|
||||
}
|
||||
if ((mPendingReplays.size() == 0) && (newInfo == null)) {
|
||||
// Nothing to update
|
||||
return;
|
||||
}
|
||||
|
||||
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
|
||||
if (app == null) {
|
||||
// Try again later
|
||||
if (DEBUG) Log.d(TAG, "app is null, delaying send");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<PackageInstallInfo> updates = new ArrayList<>();
|
||||
if (newInfo != null) {
|
||||
updates.add(newInfo);
|
||||
}
|
||||
for (int i = mPendingReplays.size() - 1; i > 0; i--) {
|
||||
InstallSessionInfo session = mPendingReplays.valueAt(i);
|
||||
if (session.getAppPackageName() != null) {
|
||||
updates.add(new PackageInstallInfo(session.getAppPackageName(),
|
||||
ShortcutInfo.PACKAGE_STATE_INSTALLING,
|
||||
(int) (session.getProgress() * 100)));
|
||||
}
|
||||
}
|
||||
mPendingReplays.clear();
|
||||
if (!updates.isEmpty()) {
|
||||
app.setPackageState(updates);
|
||||
}
|
||||
}
|
||||
|
||||
private final SessionCallback mCallback = new SessionCallback() {
|
||||
|
||||
@Override
|
||||
public void onCreated(int sessionId) {
|
||||
InstallSessionInfo session = mInstaller.getSessionInfo(sessionId);
|
||||
if (session != null) {
|
||||
mPendingReplays.put(sessionId, session);
|
||||
replayUpdates(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(int sessionId, boolean success) {
|
||||
mPendingReplays.remove(sessionId);
|
||||
InstallSessionInfo session = mInstaller.getSessionInfo(sessionId);
|
||||
if ((session != null) && (session.getAppPackageName() != null)) {
|
||||
// Replay all updates with a one time update for this installed package. No
|
||||
// need to store this record for future updates, as the app list will get
|
||||
// refreshed on resume.
|
||||
replayUpdates(new PackageInstallInfo(session.getAppPackageName(),
|
||||
success ? ShortcutInfo.PACKAGE_STATE_DEFAULT
|
||||
: ShortcutInfo.PACKAGE_STATE_ERROR, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(int sessionId, float progress) {
|
||||
InstallSessionInfo session = mInstaller.getSessionInfo(sessionId);
|
||||
if (session != null) {
|
||||
mPendingReplays.put(sessionId, session);
|
||||
replayUpdates(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpened(int sessionId) { }
|
||||
|
||||
@Override
|
||||
public void onClosed(int sessionId) { }
|
||||
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user