diff options
Diffstat (limited to 'src/com/android/launcher3/LauncherBackupHelper.java')
-rw-r--r-- | src/com/android/launcher3/LauncherBackupHelper.java | 359 |
1 files changed, 227 insertions, 132 deletions
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 11768b815..39603ad1b 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -24,7 +24,11 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.res.XmlResourceParser; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -47,10 +51,13 @@ import com.android.launcher3.backup.BackupProtos.Screen; import com.android.launcher3.backup.BackupProtos.Widget; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.util.Thunk; import com.google.protobuf.nano.InvalidProtocolBufferNanoException; import com.google.protobuf.nano.MessageNano; -import java.io.ByteArrayOutputStream; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -68,7 +75,7 @@ public class LauncherBackupHelper implements BackupHelper { private static final boolean VERBOSE = LauncherBackupAgentHelper.VERBOSE; private static final boolean DEBUG = LauncherBackupAgentHelper.DEBUG; - private static final int BACKUP_VERSION = 3; + private static final int BACKUP_VERSION = 4; private static final int MAX_JOURNAL_SIZE = 1000000; // Journal key is such that it is always smaller than any dynamically generated @@ -81,11 +88,6 @@ public class LauncherBackupHelper implements BackupHelper { /** widgets contain previews, which are very large, dribble them out */ private static final int MAX_WIDGETS_PER_PASS = 5; - private static final int IMAGE_COMPRESSION_QUALITY = 75; - - private static final Bitmap.CompressFormat IMAGE_FORMAT = - android.graphics.Bitmap.CompressFormat.PNG; - private static final String[] FAVORITE_PROJECTION = { Favorites._ID, // 0 Favorites.MODIFIED, // 1 @@ -105,6 +107,7 @@ public class LauncherBackupHelper implements BackupHelper { Favorites.SPANY, // 15 Favorites.TITLE, // 16 Favorites.PROFILE_ID, // 17 + Favorites.RANK, // 18 }; private static final int ID_INDEX = 0; @@ -124,6 +127,7 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SPANX_INDEX = 14; private static final int SPANY_INDEX = 15; private static final int TITLE_INDEX = 16; + private static final int RANK_INDEX = 18; private static final String[] SCREEN_PROJECTION = { WorkspaceScreens._ID, // 0 @@ -133,25 +137,37 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SCREEN_RANK_INDEX = 2; - private final Context mContext; + @Thunk final Context mContext; private final HashSet<String> mExistingKeys; private final ArrayList<Key> mKeys; + private final ItemTypeMatcher[] mItemTypeMatchers; + private final long mUserSerial; - private IconCache mIconCache; private BackupManager mBackupManager; private byte[] mBuffer = new byte[512]; private long mLastBackupRestoreTime; private boolean mBackupDataWasUpdated; - private DeviceProfieData mCurrentProfile; + private IconCache mIconCache; + private DeviceProfieData mDeviceProfileData; + private InvariantDeviceProfile mIdp; + boolean restoreSuccessful; int restoredBackupVersion = 1; + // When migrating from a device which different hotseat configuration, the icons are shifted + // to center along the new all-apps icon. + private int mHotseatShift = 0; + public LauncherBackupHelper(Context context) { mContext = context; mExistingKeys = new HashSet<String>(); mKeys = new ArrayList<Key>(); restoreSuccessful = true; + mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT]; + + UserManagerCompat userManager = UserManagerCompat.getInstance(mContext); + mUserSerial = userManager.getSerialNumberForUser(UserHandleCompat.myUserHandle()); } private void dataChanged() { @@ -190,10 +206,19 @@ public class LauncherBackupHelper implements BackupHelper { Journal in = readJournal(oldState); if (!launcherIsReady()) { + dataChanged(); // Perform backup later. writeJournal(newState, in); return; } + + if (mDeviceProfileData == null) { + LauncherAppState app = LauncherAppState.getInstance(); + mIdp = app.getInvariantDeviceProfile(); + mDeviceProfileData = initDeviceProfileData(mIdp); + mIconCache = app.getIconCache(); + } + Log.v(TAG, "lastBackupTime = " + in.t); mKeys.clear(); applyJournal(in); @@ -227,7 +252,7 @@ public class LauncherBackupHelper implements BackupHelper { // Check if any metadata has changed mBackupDataWasUpdated = (in.profile == null) || !Arrays.equals(DeviceProfieData.toByteArray(in.profile), - DeviceProfieData.toByteArray(getDeviceProfieData())) + DeviceProfieData.toByteArray(mDeviceProfileData)) || (in.backupVersion != BACKUP_VERSION) || (in.appVersion != getAppVersion()); } @@ -255,8 +280,7 @@ public class LauncherBackupHelper implements BackupHelper { * to this device. */ private boolean isBackupCompatible(Journal oldState) { - DeviceProfieData currentProfile = getDeviceProfieData(); - + DeviceProfieData currentProfile = mDeviceProfileData; DeviceProfieData oldProfile = oldState.profile; if (oldProfile == null || oldProfile.desktopCols == 0) { @@ -267,10 +291,15 @@ public class LauncherBackupHelper implements BackupHelper { boolean isHotsetCompatible = false; if (currentProfile.allappsRank >= oldProfile.hotseatCount) { isHotsetCompatible = true; + mHotseatShift = 0; } - if ((currentProfile.hotseatCount >= oldProfile.hotseatCount) && - (currentProfile.allappsRank == oldProfile.allappsRank)) { + + if ((currentProfile.allappsRank >= oldProfile.allappsRank) + && ((currentProfile.hotseatCount - currentProfile.allappsRank) >= + (oldProfile.hotseatCount - oldProfile.allappsRank))) { + // There is enough space on both sides of the hotseat. isHotsetCompatible = true; + mHotseatShift = currentProfile.allappsRank - oldProfile.allappsRank; } return isHotsetCompatible && (currentProfile.desktopCols >= oldProfile.desktopCols) @@ -290,6 +319,14 @@ public class LauncherBackupHelper implements BackupHelper { return; } + if (mDeviceProfileData == null) { + // This call does not happen on a looper thread. So LauncherAppState + // can't be created . Instead initialize required dependencies directly. + mIdp = new InvariantDeviceProfile(mContext); + mDeviceProfileData = initDeviceProfileData(mIdp); + mIconCache = new IconCache(mContext, mIdp); + } + int dataSize = data.size(); if (mBuffer.length < dataSize) { mBuffer = new byte[dataSize]; @@ -364,7 +401,7 @@ public class LauncherBackupHelper implements BackupHelper { journal.key = mKeys.toArray(new BackupProtos.Key[mKeys.size()]); journal.appVersion = getAppVersion(); journal.backupVersion = BACKUP_VERSION; - journal.profile = getDeviceProfieData(); + journal.profile = mDeviceProfileData; return journal; } @@ -377,23 +414,13 @@ public class LauncherBackupHelper implements BackupHelper { } } - /** - * @return the current device profile information. - */ - private DeviceProfieData getDeviceProfieData() { - if (mCurrentProfile != null) { - return mCurrentProfile; - } - final Context applicationContext = mContext.getApplicationContext(); - DeviceProfile profile = LauncherAppState.createDynamicGrid(applicationContext, null) - .getDeviceProfile(); - - mCurrentProfile = new DeviceProfieData(); - mCurrentProfile.desktopRows = profile.numRows; - mCurrentProfile.desktopCols = profile.numColumns; - mCurrentProfile.hotseatCount = profile.numHotseatIcons; - mCurrentProfile.allappsRank = profile.hotseatAllAppsRank; - return mCurrentProfile; + private DeviceProfieData initDeviceProfileData(InvariantDeviceProfile profile) { + DeviceProfieData data = new DeviceProfieData(); + data.desktopRows = profile.numRows; + data.desktopCols = profile.numColumns; + data.hotseatCount = profile.numHotseatIcons; + data.allappsRank = profile.hotseatAllAppsRank; + return data; } /** @@ -416,7 +443,10 @@ public class LauncherBackupHelper implements BackupHelper { Key key = getKey(Key.FAVORITE, id); mKeys.add(key); final String backupKey = keyToBackupKey(key); - if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime) { + + // Favorite proto changed in v4. Backup again if the version is old. + if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime + || restoredBackupVersion < 4) { writeRowToBackup(key, packFavorite(cursor), data); } else { if (DEBUG) Log.d(TAG, "favorite already backup up: " + id); @@ -443,7 +473,7 @@ public class LauncherBackupHelper implements BackupHelper { ContentResolver cr = mContext.getContentResolver(); ContentValues values = unpackFavorite(buffer, dataSize); - cr.insert(Favorites.CONTENT_URI_NO_NOTIFICATION, values); + cr.insert(Favorites.CONTENT_URI, values); } /** @@ -504,11 +534,6 @@ public class LauncherBackupHelper implements BackupHelper { */ private void backupIcons(BackupDataOutput data) throws IOException { // persist icons that haven't been persisted yet - if (!initializeIconCache()) { - dataChanged(); // try again later - if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying icon backup"); - return; - } final ContentResolver cr = mContext.getContentResolver(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); @@ -590,9 +615,11 @@ public class LauncherBackupHelper implements BackupHelper { Bitmap icon = BitmapFactory.decodeByteArray(res.data, 0, res.data.length); if (icon == null) { Log.w(TAG, "failed to unpack icon for " + key.name); + } else { + if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); + mIconCache.preloadIcon(ComponentName.unflattenFromString(key.name), icon, res.dpi, + "" /* label */, mUserSerial, mIdp); } - if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); - IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi); } /** @@ -604,17 +631,8 @@ public class LauncherBackupHelper implements BackupHelper { */ private void backupWidgets(BackupDataOutput data) throws IOException { // persist static widget info that hasn't been persisted yet - final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); - if (appState == null || !initializeIconCache()) { - Log.w(TAG, "Failed to get icon cache during restore"); - return; - } final ContentResolver cr = mContext.getContentResolver(); - final WidgetPreviewLoader previewLoader = new WidgetPreviewLoader(mContext); - final PagedViewCellLayout widgetSpacingLayout = new PagedViewCellLayout(mContext); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; - final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile(); - if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx); int backupWidgetCount = 0; String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND " @@ -626,8 +644,6 @@ public class LauncherBackupHelper implements BackupHelper { while(cursor.moveToNext()) { final long id = cursor.getLong(ID_INDEX); final String providerName = cursor.getString(APPWIDGET_PROVIDER_INDEX); - final int spanX = cursor.getInt(SPANX_INDEX); - final int spanY = cursor.getInt(SPANY_INDEX); final ComponentName provider = ComponentName.unflattenFromString(providerName); Key key = null; String backupKey = null; @@ -637,7 +653,9 @@ public class LauncherBackupHelper implements BackupHelper { } else { Log.w(TAG, "empty intent on appwidget: " + id); } - if (mExistingKeys.contains(backupKey) && restoredBackupVersion >= BACKUP_VERSION) { + + // Widget backup proto changed in v3. So add it again if the original backup is old. + if (mExistingKeys.contains(backupKey) && restoredBackupVersion >= 3) { if (DEBUG) Log.d(TAG, "already saved widget " + backupKey); // remember that we already backed this up previously @@ -646,12 +664,8 @@ public class LauncherBackupHelper implements BackupHelper { if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount); if (backupWidgetCount < MAX_WIDGETS_PER_PASS) { if (DEBUG) Log.d(TAG, "saving widget " + backupKey); - previewLoader.setPreviewSize(spanX * profile.cellWidthPx, - spanY * profile.cellHeightPx, widgetSpacingLayout); UserHandleCompat user = UserHandleCompat.myUserHandle(); - writeRowToBackup(key, - packWidget(dpi, previewLoader, mIconCache, provider, user), - data); + writeRowToBackup(key, packWidget(dpi, provider, user), data); mKeys.add(key); backupWidgetCount ++; } else { @@ -687,8 +701,8 @@ public class LauncherBackupHelper implements BackupHelper { if (icon == null) { Log.w(TAG, "failed to unpack widget icon for " + key.name); } else { - IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(widget.provider), - icon, widget.icon.dpi); + mIconCache.preloadIcon(ComponentName.unflattenFromString(widget.provider), + icon, widget.icon.dpi, widget.label, mUserSerial, mIdp); } } @@ -754,6 +768,17 @@ public class LauncherBackupHelper implements BackupHelper { return checksum.getValue(); } + /** + * @return true if its an hotseat item, that can be replaced during restore. + * TODO: Extend check for folders in hotseat. + */ + private boolean isReplaceableHotseatItem(Favorite favorite) { + return favorite.container == Favorites.CONTAINER_HOTSEAT + && favorite.intent != null + && (favorite.itemType == Favorites.ITEM_TYPE_APPLICATION + || favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT); + } + /** Serialize a Favorite for persistence, including a checksum wrapper. */ private Favorite packFavorite(Cursor c) { Favorite favorite = new Favorite(); @@ -765,30 +790,17 @@ public class LauncherBackupHelper implements BackupHelper { favorite.spanX = c.getInt(SPANX_INDEX); favorite.spanY = c.getInt(SPANY_INDEX); favorite.iconType = c.getInt(ICON_TYPE_INDEX); - if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) { - String iconPackage = c.getString(ICON_PACKAGE_INDEX); - if (!TextUtils.isEmpty(iconPackage)) { - favorite.iconPackage = iconPackage; - } - String iconResource = c.getString(ICON_RESOURCE_INDEX); - if (!TextUtils.isEmpty(iconResource)) { - favorite.iconResource = iconResource; - } - } - if (favorite.iconType == Favorites.ICON_TYPE_BITMAP) { - byte[] blob = c.getBlob(ICON_INDEX); - if (blob != null && blob.length > 0) { - favorite.icon = blob; - } - } + favorite.rank = c.getInt(RANK_INDEX); + String title = c.getString(TITLE_INDEX); if (!TextUtils.isEmpty(title)) { favorite.title = title; } String intentDescription = c.getString(INTENT_INDEX); + Intent intent = null; if (!TextUtils.isEmpty(intentDescription)) { try { - Intent intent = Intent.parseUri(intentDescription, 0); + intent = Intent.parseUri(intentDescription, 0); intent.removeExtra(ItemInfo.EXTRA_PROFILE); favorite.intent = intent.toUri(0); } catch (URISyntaxException e) { @@ -802,6 +814,47 @@ public class LauncherBackupHelper implements BackupHelper { if (!TextUtils.isEmpty(appWidgetProvider)) { favorite.appWidgetProvider = appWidgetProvider; } + } else if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) { + if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) { + String iconPackage = c.getString(ICON_PACKAGE_INDEX); + if (!TextUtils.isEmpty(iconPackage)) { + favorite.iconPackage = iconPackage; + } + String iconResource = c.getString(ICON_RESOURCE_INDEX); + if (!TextUtils.isEmpty(iconResource)) { + favorite.iconResource = iconResource; + } + } + + byte[] blob = c.getBlob(ICON_INDEX); + if (blob != null && blob.length > 0) { + favorite.icon = blob; + } + } + + if (isReplaceableHotseatItem(favorite)) { + if (intent != null && intent.getComponent() != null) { + PackageManager pm = mContext.getPackageManager(); + ActivityInfo activity = null;; + try { + activity = pm.getActivityInfo(intent.getComponent(), 0); + } catch (NameNotFoundException e) { + Log.e(TAG, "Target not found", e); + } + if (activity == null) { + return favorite; + } + for (int i = 0; i < mItemTypeMatchers.length; i++) { + if (mItemTypeMatchers[i] == null) { + mItemTypeMatchers[i] = new ItemTypeMatcher( + CommonAppTypeParser.getResourceForItemType(i)); + } + if (mItemTypeMatchers[i].matches(activity, pm)) { + favorite.targetType = i; + break; + } + } + } } return favorite; @@ -811,6 +864,12 @@ public class LauncherBackupHelper implements BackupHelper { private ContentValues unpackFavorite(byte[] buffer, int dataSize) throws IOException { Favorite favorite = unpackProto(new Favorite(), buffer, dataSize); + + // If it is a hotseat item, move it accordingly. + if (favorite.container == Favorites.CONTAINER_HOTSEAT) { + favorite.screen += mHotseatShift; + } + ContentValues values = new ContentValues(); values.put(Favorites._ID, favorite.id); values.put(Favorites.SCREEN, favorite.screen); @@ -819,14 +878,17 @@ public class LauncherBackupHelper implements BackupHelper { values.put(Favorites.CELLY, favorite.cellY); values.put(Favorites.SPANX, favorite.spanX); values.put(Favorites.SPANY, favorite.spanY); - values.put(Favorites.ICON_TYPE, favorite.iconType); - if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) { - values.put(Favorites.ICON_PACKAGE, favorite.iconPackage); - values.put(Favorites.ICON_RESOURCE, favorite.iconResource); - } - if (favorite.iconType == Favorites.ICON_TYPE_BITMAP) { + values.put(Favorites.RANK, favorite.rank); + + if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) { + values.put(Favorites.ICON_TYPE, favorite.iconType); + if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) { + values.put(Favorites.ICON_PACKAGE, favorite.iconPackage); + values.put(Favorites.ICON_RESOURCE, favorite.iconResource); + } values.put(Favorites.ICON, favorite.icon); } + if (!TextUtils.isEmpty(favorite.title)) { values.put(Favorites.TITLE, favorite.title); } else { @@ -842,7 +904,7 @@ public class LauncherBackupHelper implements BackupHelper { UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle); values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber); - DeviceProfieData currentProfile = getDeviceProfieData(); + DeviceProfieData currentProfile = mDeviceProfileData; if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) { if (!TextUtils.isEmpty(favorite.appWidgetProvider)) { @@ -861,8 +923,17 @@ public class LauncherBackupHelper implements BackupHelper { throw new InvalidBackupException("Widget not in screen bounds, aborting restore"); } } else { - // Let LauncherModel know we've been here. - values.put(LauncherSettings.Favorites.RESTORED, 1); + // Check if it is an hotseat item, that can be replaced. + if (isReplaceableHotseatItem(favorite) + && favorite.targetType != Favorite.TARGET_NONE + && favorite.targetType < CommonAppTypeParser.SUPPORTED_TYPE_COUNT) { + Log.e(TAG, "Added item type flag"); + values.put(LauncherSettings.Favorites.RESTORED, + 1 | CommonAppTypeParser.encodeItemTypeToFlag(favorite.targetType)); + } else { + // Let LauncherModel know we've been here. + values.put(LauncherSettings.Favorites.RESTORED, 1); + } // Verify placement if (favorite.container == Favorites.CONTAINER_HOTSEAT) { @@ -905,16 +976,12 @@ public class LauncherBackupHelper implements BackupHelper { private Resource packIcon(int dpi, Bitmap icon) { Resource res = new Resource(); res.dpi = dpi; - ByteArrayOutputStream os = new ByteArrayOutputStream(); - if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) { - res.data = os.toByteArray(); - } + res.data = Utilities.flattenBitmap(icon); return res; } /** Serialize a widget for persistence, including a checksum wrapper. */ - private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache, - ComponentName provider, UserHandleCompat user) { + private Widget packWidget(int dpi, ComponentName provider, UserHandleCompat user) { final LauncherAppWidgetProviderInfo info = LauncherModel.getProviderInfo(mContext, provider, user); Widget widget = new Widget(); @@ -923,28 +990,21 @@ public class LauncherBackupHelper implements BackupHelper { widget.configure = info.configure != null; if (info.icon != 0) { widget.icon = new Resource(); - Drawable fullResIcon = iconCache.getFullResIcon(provider.getPackageName(), info.icon); + Drawable fullResIcon = mIconCache.getFullResIcon(provider.getPackageName(), info.icon); Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) { - widget.icon.data = os.toByteArray(); - widget.icon.dpi = dpi; - } - } - if (info.previewImage != 0) { - widget.preview = new Resource(); - Bitmap preview = previewLoader.generateWidgetPreview(info, null); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - if (preview.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) { - widget.preview.data = os.toByteArray(); - widget.preview.dpi = dpi; - } + widget.icon.data = Utilities.flattenBitmap(icon); + widget.icon.dpi = dpi; } + // Calculate the spans corresponding to any one of the orientations as it should not change + // based on orientation. + int[] minSpans = CellLayout.rectToCell( + mIdp.portraitProfile, mContext, info.minResizeWidth, info.minResizeHeight, null); widget.minSpanX = (info.resizeMode & LauncherAppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0 - ? info.minSpanX : -1; + ? minSpans[0] : -1; widget.minSpanY = (info.resizeMode & LauncherAppWidgetProviderInfo.RESIZE_VERTICAL) != 0 - ? info.minSpanY : -1; + ? minSpans[1] : -1; + return widget; } @@ -1090,23 +1150,6 @@ public class LauncherBackupHelper implements BackupHelper { return wrapper.payload; } - private boolean initializeIconCache() { - if (mIconCache != null) { - return true; - } - - final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); - if (appState == null) { - Throwable stackTrace = new Throwable(); - stackTrace.fillInStackTrace(); - Log.w(TAG, "Failed to get app state during backup/restore", stackTrace); - return false; - } - mIconCache = appState.getIconCache(); - return mIconCache != null; - } - - /** * @return true if the launcher is in a state to support backup */ @@ -1119,9 +1162,8 @@ public class LauncherBackupHelper implements BackupHelper { } cursor.close(); - if (!initializeIconCache()) { + if (LauncherAppState.getInstanceNoCreate() == null) { // launcher services are unavailable, try again later - dataChanged(); return false; } @@ -1133,13 +1175,66 @@ public class LauncherBackupHelper implements BackupHelper { .getSerialNumberForUser(UserHandleCompat.myUserHandle()); } - private class InvalidBackupException extends IOException { - private InvalidBackupException(Throwable cause) { + @Thunk class InvalidBackupException extends IOException { + + private static final long serialVersionUID = 8931456637211665082L; + + @Thunk InvalidBackupException(Throwable cause) { super(cause); } - public InvalidBackupException(String reason) { + @Thunk InvalidBackupException(String reason) { super(reason); } } + + /** + * A class to check if an activity can handle one of the intents from a list of + * predefined intents. + */ + private class ItemTypeMatcher { + + private final ArrayList<Intent> mIntents; + + ItemTypeMatcher(int xml_res) { + mIntents = xml_res == 0 ? new ArrayList<Intent>() : parseIntents(xml_res); + } + + private ArrayList<Intent> parseIntents(int xml_res) { + ArrayList<Intent> intents = new ArrayList<Intent>(); + XmlResourceParser parser = mContext.getResources().getXml(xml_res); + try { + DefaultLayoutParser.beginDocument(parser, DefaultLayoutParser.TAG_RESOLVE); + final int depth = parser.getDepth(); + int type; + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if (type != XmlPullParser.START_TAG) { + continue; + } else if (DefaultLayoutParser.TAG_FAVORITE.equals(parser.getName())) { + final String uri = DefaultLayoutParser.getAttributeValue( + parser, DefaultLayoutParser.ATTR_URI); + intents.add(Intent.parseUri(uri, 0)); + } + } + } catch (URISyntaxException | XmlPullParserException | IOException e) { + Log.e(TAG, "Unable to parse " + xml_res, e); + } finally { + parser.close(); + } + return intents; + } + + public boolean matches(ActivityInfo activity, PackageManager pm) { + for (Intent intent : mIntents) { + intent.setPackage(activity.packageName); + ResolveInfo info = pm.resolveActivity(intent, 0); + if (info != null && (info.activityInfo.name.equals(activity.name) + || info.activityInfo.name.equals(activity.targetActivity))) { + return true; + } + } + return false; + } + } } |