summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/values/strings.xml17
-rw-r--r--src/com/android/launcher3/BubbleTextView.java34
-rw-r--r--src/com/android/launcher3/Folder.java1
-rw-r--r--src/com/android/launcher3/Launcher.java52
-rw-r--r--src/com/android/launcher3/LauncherModel.java7
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java32
-rw-r--r--src/com/android/launcher3/Workspace.java41
7 files changed, 159 insertions, 25 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ad3a1c4fb..b7f4505a9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -277,4 +277,21 @@ s -->
<string name="package_state_unknown">Unknown</string>
<!-- Label on an icon that references an uninstalled package, for which restore from market has failed. [CHAR_LIMIT=15] -->
<string name="package_state_error">Not restored</string>
+
+ <!-- Button for abandoned promises dialog, that removes all abandoned promise icons. -->
+ <string name="abandoned_clean_all">Remove All</string>
+ <!-- Button for abandoned promises dialog, to removes this abandoned promise icon. -->
+ <string name="abandoned_clean_this">Remove</string>
+ <!-- Button for abandoned promise dialog, to search in the market for the missing package. -->
+ <string name="abandoned_search">Search</string>
+ <!-- Title for abandoned promise dialog. -->
+ <string name="abandoned_promises_title">This Package is not Installed</string>
+ <!-- Explanation for abandoned promise dialog. -->
+ <plurals name="abandoned_promises_explanation">
+ <item quantity="one">The package for this icon is not installed. You many remove it, or
+ attempt to search for the package and install it manually.</item>
+ <item quantity="other">The package for this icon is not installed. You many remove all
+ similarly broken icons, remove only this icon, or attempt to search for the package and
+ install it manually.</item>
+ </plurals>
</resources>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 95300c133..992ac5897 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -74,8 +74,6 @@ public class BubbleTextView extends TextView {
private CheckLongPressHelper mLongPressHelper;
private int mInstallState;
- private int mState;
-
private CharSequence mDefaultText = "";
public BubbleTextView(Context context) {
@@ -124,10 +122,9 @@ public class BubbleTextView extends TextView {
Drawable iconDrawable = Utilities.createIconDrawable(b);
setCompoundDrawables(null, iconDrawable, null, null);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
- setText(info.title);
setTag(info);
if (info.isPromise()) {
- setState(ShortcutInfo.PACKAGE_STATE_UNKNOWN); // TODO: persist this state somewhere
+ applyState();
}
}
@@ -150,6 +147,11 @@ public class BubbleTextView extends TextView {
LauncherModel.checkItemInfo((ItemInfo) tag);
}
super.setTag(tag);
+ if (tag instanceof ShortcutInfo) {
+ final ShortcutInfo info = (ShortcutInfo) tag;
+ mDefaultText = info.title;
+ setText(mDefaultText);
+ }
}
@Override
@@ -415,19 +417,12 @@ public class BubbleTextView extends TextView {
mLongPressHelper.cancelLongPress();
}
- public void setState(int state) {
- if (mState == ShortcutInfo.PACKAGE_STATE_DEFAULT && mState != state) {
- mDefaultText = getText();
- }
- mState = state;
- applyState();
- }
-
- private void applyState() {
+ public void applyState() {
int alpha = getResources().getInteger(R.integer.promise_icon_alpha);
- if (DEBUG) Log.d(TAG, "applying icon state: " + mState);
+ final int state = getState();
+ if (DEBUG) Log.d(TAG, "applying icon state: " + state);
- switch(mState) {
+ switch(state) {
case ShortcutInfo.PACKAGE_STATE_DEFAULT:
super.setText(mDefaultText);
alpha = 255;
@@ -462,4 +457,13 @@ public class BubbleTextView extends TextView {
}
}
}
+
+ private int getState() {
+ if (! (getTag() instanceof ShortcutInfo)) {
+ return ShortcutInfo.PACKAGE_STATE_DEFAULT;
+ } else {
+ ShortcutInfo info = (ShortcutInfo) getTag();
+ return info.getState();
+ }
+ }
}
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index e900c2b5a..896be70cf 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -575,6 +575,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
textView.setTextColor(getResources().getColor(R.color.folder_items_text_color));
textView.setShadowsEnabled(false);
textView.setGlowColor(getResources().getColor(R.color.folder_items_glow_color));
+ textView.applyState();
textView.setOnClickListener(this);
textView.setOnLongClickListener(this);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f8c9f7b38..4ca3c5092 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -28,6 +28,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.AlertDialog;
import android.app.SearchManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
@@ -38,6 +39,7 @@ import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -2517,7 +2519,7 @@ public class Launcher extends Activity
*
* @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
*/
- protected void onClickAppShortcut(View v) {
+ protected void onClickAppShortcut(final View v) {
if (LOGD) Log.d(TAG, "onClickAppShortcut");
Object tag = v.getTag();
if (!(tag instanceof ShortcutInfo)) {
@@ -2541,7 +2543,55 @@ public class Launcher extends Activity
}
}
+ // Check for abandoned promise
+ if (shortcut.isAbandoned() && v instanceof BubbleTextView) {
+ final ArrayList<BubbleTextView> abandoned =
+ mWorkspace.getAbandonedPromises(new ArrayList<BubbleTextView>());
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.abandoned_promises_title);
+ builder.setMessage(getResources().getQuantityString(
+ R.plurals.abandoned_promises_explanation, abandoned.size()));
+ builder.setPositiveButton(R.string.abandoned_search,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ startAppShortcutActivity(v);
+ }
+ }
+ );
+ if (abandoned.size() > 1) {
+ builder.setNegativeButton(R.string.abandoned_clean_all,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ final UserHandleCompat user = UserHandleCompat.myUserHandle();
+ mWorkspace.removeAbandonedPromises(abandoned, user);
+ }
+ }
+ );
+ }
+ builder.setNeutralButton(R.string.abandoned_clean_this,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ final BubbleTextView bubble = (BubbleTextView) v;
+ final UserHandleCompat user = UserHandleCompat.myUserHandle();
+ mWorkspace.removeAbandonedPromise(bubble, user);
+ }
+ });
+ builder.create().show();
+ return;
+ }
+
// Start activities
+ startAppShortcutActivity(v);
+ }
+
+ private void startAppShortcutActivity(View v) {
+ Object tag = v.getTag();
+ if (!(tag instanceof ShortcutInfo)) {
+ throw new IllegalArgumentException("Input must be a Shortcut");
+ }
+ final ShortcutInfo shortcut = (ShortcutInfo) tag;
+ final Intent intent = shortcut.intent;
+
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1],
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 07389c9a7..4d0ec78dd 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2975,6 +2975,7 @@ public class LauncherModel extends BroadcastReceiver
info.setIcon(mIconCache.getIcon(intent, info.title.toString(), info.user));
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
info.restoredIntent = intent;
+ info.setState(ShortcutInfo.PACKAGE_STATE_UNKNOWN);
return info;
}
@@ -3088,6 +3089,9 @@ public class LauncherModel extends BroadcastReceiver
if (i instanceof ShortcutInfo) {
ShortcutInfo info = (ShortcutInfo) i;
ComponentName cn = info.intent.getComponent();
+ if (info.restoredIntent != null) {
+ cn = info.restoredIntent.getComponent();
+ }
if (cn != null && f.filterItem(null, info, cn)) {
filtered.add(info);
}
@@ -3095,6 +3099,9 @@ public class LauncherModel extends BroadcastReceiver
FolderInfo info = (FolderInfo) i;
for (ShortcutInfo s : info.contents) {
ComponentName cn = s.intent.getComponent();
+ if (s.restoredIntent != null) {
+ cn = s.restoredIntent.getComponent();
+ }
if (cn != null && f.filterItem(info, s, cn)) {
filtered.add(s);
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index f40cf9fa1..a84a90354 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -36,22 +36,22 @@ import java.util.Arrays;
*/
public class ShortcutInfo extends ItemInfo {
- /** This package is not installed, and there is no other information available. */
+ /** {@link #mState} meaning this package is not installed, and there is no other information. */
public static final int PACKAGE_STATE_UNKNOWN = -2;
- /** This package is not installed, because installation failed. */
+ /** {@link #mState} meaning this package is not installed, because installation failed. */
public static final int PACKAGE_STATE_ERROR = -1;
- /** This package is installed. This is the typical case */
+ /** {@link #mState} meaning this package is installed. This is the typical case. */
public static final int PACKAGE_STATE_DEFAULT = 0;
- /** This package is not installed, but some external entity has promised to install it. */
+ /** {@link #mState} meaning some external entity has promised to install this package. */
public static final int PACKAGE_STATE_ENQUEUED = 1;
- /** This package is not installed, but some external entity is downloading it. */
+ /** {@link #mState} meaning but some external entity is downloading this package. */
public static final int PACKAGE_STATE_DOWNLOADING = 2;
- /** This package is not installed, but some external entity is installing it. */
+ /** {@link #mState} meaning some external entity is installing this package. */
public static final int PACKAGE_STATE_INSTALLING = 3;
/**
@@ -82,6 +82,11 @@ public class ShortcutInfo extends ItemInfo {
*/
private Bitmap mIcon;
+ /**
+ * The installation state of the package that this shortcut represents.
+ */
+ protected int mState;
+
long firstInstallTime;
int flags = 0;
@@ -110,6 +115,7 @@ public class ShortcutInfo extends ItemInfo {
if (restoredIntent != null) {
intent = restoredIntent;
restoredIntent = null;
+ mState = PACKAGE_STATE_DEFAULT;
}
}
@@ -218,5 +224,19 @@ public class ShortcutInfo extends ItemInfo {
&& pkgName != null
&& pkgName.equals(restoredIntent.getComponent().getPackageName());
}
+
+ public boolean isAbandoned() {
+ return isPromise()
+ && (mState == ShortcutInfo.PACKAGE_STATE_ERROR
+ || mState == ShortcutInfo.PACKAGE_STATE_UNKNOWN);
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ public void setState(int state) {
+ mState = state;
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6afea8268..74ef1d46b 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -98,8 +98,8 @@ public class Workspace extends SmoothPagedView
private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
- private static final boolean MAP_NO_RECURSE = false;
- private static final boolean MAP_RECURSE = true;
+ static final boolean MAP_NO_RECURSE = false;
+ static final boolean MAP_RECURSE = true;
// These animators are used to fade the children's outlines
private ObjectAnimator mChildrenOutlineFadeInAnimation;
@@ -4857,6 +4857,40 @@ public class Workspace extends SmoothPagedView
});
}
+ ArrayList<BubbleTextView> getAbandonedPromises(final ArrayList<BubbleTextView> abandoned) {
+ mapOverShortcuts(Workspace.MAP_RECURSE, new Workspace.ShortcutOperator() {
+ @Override
+ public boolean evaluate(ItemInfo info, View view, View parent) {
+ if (info instanceof ShortcutInfo
+ && ((ShortcutInfo) info).isAbandoned()
+ && view instanceof BubbleTextView) {
+ abandoned.add((BubbleTextView) view);
+ }
+ return false;
+ }
+ });
+ return abandoned;
+ }
+ public void removeAbandonedPromise(BubbleTextView view, UserHandleCompat user) {
+ ArrayList<BubbleTextView> views = new ArrayList<BubbleTextView>(1);
+ views.add(view);
+ removeAbandonedPromises(views, user);
+ }
+
+ public void removeAbandonedPromises(ArrayList<BubbleTextView> views, UserHandleCompat user) {
+ HashSet<ComponentName> cns = new HashSet<ComponentName>(views.size());
+ for (final BubbleTextView bubble : views) {
+ if (bubble.getTag() != null && bubble.getTag() instanceof ShortcutInfo) {
+ final ShortcutInfo shortcut = (ShortcutInfo) bubble.getTag();
+ if (shortcut.isAbandoned()) {
+ cns.add(shortcut.getRestoredIntent().getComponent());
+ LauncherModel.deleteItemFromDatabase(mLauncher, shortcut);
+ }
+ }
+ }
+ removeItemsByComponentName(cns, user);
+ }
+
public void updatePackageState(final String pkgName, final int state) {
mapOverShortcuts(MAP_RECURSE, new ShortcutOperator() {
@Override
@@ -4864,7 +4898,8 @@ public class Workspace extends SmoothPagedView
if (info instanceof ShortcutInfo
&& ((ShortcutInfo) info).isPromiseFor(pkgName)
&& v instanceof BubbleTextView) {
- ((BubbleTextView)v).setState(state);
+ ((ShortcutInfo) info).setState(state);
+ ((BubbleTextView)v).applyState();
}
// process all the shortcuts
return false;