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() {
|
public void applyState() {
|
||||||
final int progressLevel;
|
if (getTag() instanceof ShortcutInfo) {
|
||||||
final int state = getState();
|
ShortcutInfo info = (ShortcutInfo) getTag();
|
||||||
if (DEBUG) Log.d(TAG, "applying icon state: " + state);
|
final int state = info.getState();
|
||||||
|
|
||||||
switch(state) {
|
final int progressLevel;
|
||||||
case ShortcutInfo.PACKAGE_STATE_DEFAULT:
|
if (DEBUG) Log.d(TAG, "applying icon state: " + state);
|
||||||
super.setText(mDefaultText);
|
|
||||||
progressLevel = 100;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ShortcutInfo.PACKAGE_STATE_ENQUEUED:
|
switch(state) {
|
||||||
setText(R.string.package_state_enqueued);
|
case ShortcutInfo.PACKAGE_STATE_DEFAULT:
|
||||||
progressLevel = 0;
|
progressLevel = 100;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShortcutInfo.PACKAGE_STATE_DOWNLOADING:
|
case ShortcutInfo.PACKAGE_STATE_INSTALLING:
|
||||||
setText(R.string.package_state_downloading);
|
setText(R.string.package_state_installing);
|
||||||
// TODO(sunnygoyal): fix progress
|
progressLevel = info.getProgress();
|
||||||
progressLevel = 30;
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case ShortcutInfo.PACKAGE_STATE_INSTALLING:
|
case ShortcutInfo.PACKAGE_STATE_ERROR:
|
||||||
setText(R.string.package_state_installing);
|
case ShortcutInfo.PACKAGE_STATE_UNKNOWN:
|
||||||
progressLevel = 100;
|
default:
|
||||||
break;
|
progressLevel = 0;
|
||||||
|
setText(R.string.package_state_unknown);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ShortcutInfo.PACKAGE_STATE_ERROR:
|
Drawable[] drawables = getCompoundDrawables();
|
||||||
setText(R.string.package_state_error);
|
Drawable top = drawables[1];
|
||||||
progressLevel = 0;
|
if (top != null) {
|
||||||
break;
|
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:
|
preloadDrawable.setLevel(progressLevel);
|
||||||
default:
|
if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
|
||||||
progressLevel = 0;
|
preloadDrawable.maybePerformFinishedAnimation();
|
||||||
setText(R.string.package_state_unknown);
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.MotionEvent;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewAnimationUtils;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.View.OnLongClickListener;
|
import android.view.View.OnLongClickListener;
|
||||||
|
import android.view.ViewAnimationUtils;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||||
@@ -93,9 +92,7 @@ import android.view.Window;
|
|||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||||
import android.view.animation.AccelerateInterpolator;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
import android.view.animation.DecelerateInterpolator;
|
||||||
import android.view.animation.LinearInterpolator;
|
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Advanceable;
|
import android.widget.Advanceable;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
@@ -107,10 +104,10 @@ import com.android.launcher3.DropTarget.DragObject;
|
|||||||
import com.android.launcher3.PagedView.PageSwitchListener;
|
import com.android.launcher3.PagedView.PageSwitchListener;
|
||||||
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
||||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
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.UserHandleCompat;
|
||||||
import com.android.launcher3.compat.UserManagerCompat;
|
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.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@@ -1055,12 +1052,15 @@ public class Launcher extends Activity
|
|||||||
}
|
}
|
||||||
mWorkspace.updateInteractionForState();
|
mWorkspace.updateInteractionForState();
|
||||||
mWorkspace.onResume();
|
mWorkspace.onResume();
|
||||||
|
|
||||||
|
PackageInstallerCompat.getInstance(this).onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
// Ensure that items added to Launcher are queued until Launcher returns
|
// Ensure that items added to Launcher are queued until Launcher returns
|
||||||
InstallShortcutReceiver.enableInstallQueue();
|
InstallShortcutReceiver.enableInstallQueue();
|
||||||
|
PackageInstallerCompat.getInstance(this).onPause();
|
||||||
|
|
||||||
super.onPause();
|
super.onPause();
|
||||||
mPaused = true;
|
mPaused = true;
|
||||||
@@ -2028,6 +2028,7 @@ public class Launcher extends Activity
|
|||||||
mWorkspace = null;
|
mWorkspace = null;
|
||||||
mDragController = null;
|
mDragController = null;
|
||||||
|
|
||||||
|
PackageInstallerCompat.getInstance(this).onStop();
|
||||||
LauncherAnimUtils.onDestroyActivity();
|
LauncherAnimUtils.onDestroyActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4478,6 +4479,7 @@ public class Launcher extends Activity
|
|||||||
mWorkspace.getUniqueComponents(true, null);
|
mWorkspace.getUniqueComponents(true, null);
|
||||||
mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
|
mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
|
||||||
}
|
}
|
||||||
|
PackageInstallerCompat.getInstance(this).onFinishBind();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLoadingCompleteBroadcastIfNecessary() {
|
private void sendLoadingCompleteBroadcastIfNecessary() {
|
||||||
@@ -4591,9 +4593,10 @@ public class Launcher extends Activity
|
|||||||
*
|
*
|
||||||
* Implementation of the method from LauncherModel.Callbacks.
|
* Implementation of the method from LauncherModel.Callbacks.
|
||||||
*/
|
*/
|
||||||
public void updatePackageState(String pkgName, int state) {
|
@Override
|
||||||
|
public void updatePackageState(ArrayList<PackageInstallInfo> installInfo) {
|
||||||
if (mWorkspace != null) {
|
if (mWorkspace != null) {
|
||||||
mWorkspace.updatePackageState(pkgName, state);
|
mWorkspace.updatePackageState(installInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,11 @@
|
|||||||
package com.android.launcher3;
|
package com.android.launcher3;
|
||||||
|
|
||||||
import android.app.SearchManager;
|
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.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
@@ -25,8 +29,10 @@ import android.os.Handler;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||||
|
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
||||||
private static final String TAG = "LauncherAppState";
|
private static final String TAG = "LauncherAppState";
|
||||||
@@ -251,8 +257,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
|||||||
return getInstance().mBuildInfo.isDogfoodBuild();
|
return getInstance().mBuildInfo.isDogfoodBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageState(String pkgName, int state) {
|
public void setPackageState(ArrayList<PackageInstallInfo> installInfo) {
|
||||||
if (DEBUG) Log.d(TAG, "setPackageState(" + pkgName + ", " + state + ")");
|
mModel.setPackageState(installInfo);
|
||||||
mModel.setPackageState(pkgName, state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import android.util.Pair;
|
|||||||
import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
|
import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
|
||||||
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
||||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||||
|
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||||
import com.android.launcher3.compat.UserHandleCompat;
|
import com.android.launcher3.compat.UserHandleCompat;
|
||||||
import com.android.launcher3.compat.UserManagerCompat;
|
import com.android.launcher3.compat.UserManagerCompat;
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ public class LauncherModel extends BroadcastReceiver
|
|||||||
ArrayList<ItemInfo> addAnimated,
|
ArrayList<ItemInfo> addAnimated,
|
||||||
ArrayList<AppInfo> addedApps);
|
ArrayList<AppInfo> addedApps);
|
||||||
public void bindAppsUpdated(ArrayList<AppInfo> apps);
|
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,
|
public void bindComponentsRemoved(ArrayList<String> packageNames,
|
||||||
ArrayList<AppInfo> appInfos, UserHandleCompat user);
|
ArrayList<AppInfo> appInfos, UserHandleCompat user);
|
||||||
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
|
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
|
||||||
@@ -332,13 +333,13 @@ public class LauncherModel extends BroadcastReceiver
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageState(final String pkgName, final int state) {
|
public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {
|
||||||
// Process the updated package state
|
// Process the updated package state
|
||||||
Runnable r = new Runnable() {
|
Runnable r = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
|
Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
|
||||||
if (callbacks != 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;
|
public static final int PACKAGE_STATE_DEFAULT = 0;
|
||||||
|
|
||||||
/** {@link #mState} meaning some external entity has promised to install this package. */
|
/** {@link #mState} meaning some external entity has promised to install this package. */
|
||||||
public static final int PACKAGE_STATE_ENQUEUED = 1;
|
public static final int PACKAGE_STATE_INSTALLING = 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The intent used to start the application.
|
* The intent used to start the application.
|
||||||
@@ -89,6 +83,11 @@ public class ShortcutInfo extends ItemInfo {
|
|||||||
*/
|
*/
|
||||||
protected int mState;
|
protected int mState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The installation progress [0-100] of the package that this shortcut represents.
|
||||||
|
*/
|
||||||
|
protected int mProgress;
|
||||||
|
|
||||||
long firstInstallTime;
|
long firstInstallTime;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
@@ -237,16 +236,24 @@ public class ShortcutInfo extends ItemInfo {
|
|||||||
|
|
||||||
public boolean isAbandoned() {
|
public boolean isAbandoned() {
|
||||||
return isPromise()
|
return isPromise()
|
||||||
&& (mState == ShortcutInfo.PACKAGE_STATE_ERROR
|
&& (mState == PACKAGE_STATE_ERROR
|
||||||
|| mState == ShortcutInfo.PACKAGE_STATE_UNKNOWN);
|
|| mState == PACKAGE_STATE_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getState() {
|
public int getProgress() {
|
||||||
return mState;
|
return mProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(int progress) {
|
||||||
|
mProgress = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setState(int state) {
|
public void setState(int state) {
|
||||||
mState = 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.FolderIcon.FolderRingAnimator;
|
||||||
import com.android.launcher3.Launcher.CustomContentCallbacks;
|
import com.android.launcher3.Launcher.CustomContentCallbacks;
|
||||||
import com.android.launcher3.LauncherSettings.Favorites;
|
import com.android.launcher3.LauncherSettings.Favorites;
|
||||||
|
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||||
import com.android.launcher3.compat.UserHandleCompat;
|
import com.android.launcher3.compat.UserHandleCompat;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -4864,26 +4865,32 @@ public class Workspace extends SmoothPagedView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePackageState(final String pkgName, final int state) {
|
public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {
|
||||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
HashSet<String> completedPackages = new HashSet<>();
|
||||||
@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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
|
for (final PackageInstallInfo installInfo : installInfos) {
|
||||||
// Update any pending widget
|
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||||
HashSet<String> packages = new HashSet<String>();
|
@Override
|
||||||
packages.add(pkgName);
|
public boolean evaluate(ItemInfo info, View v, View parent) {
|
||||||
restorePendingWidgets(packages);
|
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.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
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.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class LauncherAppsCompat {
|
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