diff options
Diffstat (limited to 'src/com/android/launcher3/provider/ImportDataTask.java')
-rw-r--r-- | src/com/android/launcher3/provider/ImportDataTask.java | 438 |
1 files changed, 0 insertions, 438 deletions
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java deleted file mode 100644 index c9af2fe6fc..0000000000 --- a/src/com/android/launcher3/provider/ImportDataTask.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2016 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.provider; - -import static com.android.launcher3.Utilities.getDevicePrefs; - -import android.content.ContentProviderOperation; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ProviderInfo; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.Process; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.SparseBooleanArray; - -import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; -import com.android.launcher3.DefaultLayoutParser; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherProvider; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.LauncherSettings.Settings; -import com.android.launcher3.Workspace; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.logging.FileLog; -import com.android.launcher3.model.GridSizeMigrationTask; -import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.pm.UserCache; -import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.IntSparseArrayMap; -import com.android.launcher3.util.PackageManagerHelper; - -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashSet; - -/** - * Utility class to import data from another Launcher which is based on Launcher3 schema. - */ -public class ImportDataTask { - - public static final String KEY_DATA_IMPORT_SRC_PKG = "data_import_src_pkg"; - public static final String KEY_DATA_IMPORT_SRC_AUTHORITY = "data_import_src_authority"; - - private static final String TAG = "ImportDataTask"; - private static final int MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION = 6; - // Insert items progressively to avoid OOM exception when loading icons. - private static final int BATCH_INSERT_SIZE = 15; - - private final Context mContext; - - private final Uri mOtherFavoritesUri; - - private int mHotseatSize; - private int mMaxGridSizeX; - private int mMaxGridSizeY; - - private ImportDataTask(Context context, String sourceAuthority) { - mContext = context; - mOtherFavoritesUri = Uri.parse("content://" + sourceAuthority + "/" + Favorites.TABLE_NAME); - } - - public boolean importWorkspace() throws Exception { - FileLog.d(TAG, "Importing DB from " + mOtherFavoritesUri); - - mHotseatSize = mMaxGridSizeX = mMaxGridSizeY = 0; - importWorkspaceItems(); - GridSizeMigrationTask.markForMigration(mContext, mMaxGridSizeX, mMaxGridSizeY, mHotseatSize); - - // Create empty DB flag. - LauncherSettings.Settings.call(mContext.getContentResolver(), - LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG); - return true; - } - - /** - * 1) Imports all the workspace entries from the source provider. - * 2) For home screen entries, maps the screen id based on {@param screenIdMap} - * 3) In the end fills any holes in hotseat with items from default hotseat layout. - */ - private void importWorkspaceItems() throws Exception { - String profileId = Long.toString(UserCache.INSTANCE.get(mContext) - .getSerialNumberForUser(Process.myUserHandle())); - - boolean createEmptyRowOnFirstScreen; - if (FeatureFlags.QSB_ON_FIRST_SCREEN) { - try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null, - // get items on the first row of the first screen (min screen id) - "profileId = ? AND container = -100 AND cellY = 0 AND screen = " + - "(SELECT MIN(screen) FROM favorites WHERE container = -100)", - new String[]{profileId}, - null)) { - // First row of first screen is not empty - createEmptyRowOnFirstScreen = c.moveToNext(); - } - } else { - createEmptyRowOnFirstScreen = false; - } - - ArrayList<ContentProviderOperation> insertOperations = new ArrayList<>(BATCH_INSERT_SIZE); - - // Set of package names present in hotseat - final HashSet<String> hotseatTargetApps = new HashSet<>(); - int maxId = 0; - - // Number of imported items on workspace and hotseat - int totalItemsOnWorkspace = 0; - - try (Cursor c = mContext.getContentResolver() - .query(mOtherFavoritesUri, null, - // Only migrate the primary user - Favorites.PROFILE_ID + " = ?", new String[]{profileId}, - // Get the items sorted by container, so that the folders are loaded - // before the corresponding items. - Favorites.CONTAINER + " , " + Favorites.SCREEN)) { - - // various columns we expect to exist. - final int idIndex = c.getColumnIndexOrThrow(Favorites._ID); - final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT); - final int titleIndex = c.getColumnIndexOrThrow(Favorites.TITLE); - final int containerIndex = c.getColumnIndexOrThrow(Favorites.CONTAINER); - final int itemTypeIndex = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE); - final int widgetProviderIndex = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER); - final int screenIndex = c.getColumnIndexOrThrow(Favorites.SCREEN); - final int cellXIndex = c.getColumnIndexOrThrow(Favorites.CELLX); - final int cellYIndex = c.getColumnIndexOrThrow(Favorites.CELLY); - final int spanXIndex = c.getColumnIndexOrThrow(Favorites.SPANX); - final int spanYIndex = c.getColumnIndexOrThrow(Favorites.SPANY); - final int rankIndex = c.getColumnIndexOrThrow(Favorites.RANK); - final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON); - final int iconPackageIndex = c.getColumnIndexOrThrow(Favorites.ICON_PACKAGE); - final int iconResourceIndex = c.getColumnIndexOrThrow(Favorites.ICON_RESOURCE); - - SparseBooleanArray mValidFolders = new SparseBooleanArray(); - ContentValues values = new ContentValues(); - - Integer firstScreenId = null; - while (c.moveToNext()) { - values.clear(); - int id = c.getInt(idIndex); - maxId = Math.max(maxId, id); - int type = c.getInt(itemTypeIndex); - int container = c.getInt(containerIndex); - - int screen = c.getInt(screenIndex); - - int cellX = c.getInt(cellXIndex); - int cellY = c.getInt(cellYIndex); - int spanX = c.getInt(spanXIndex); - int spanY = c.getInt(spanYIndex); - - switch (container) { - case Favorites.CONTAINER_DESKTOP: { - if (screen < Workspace.FIRST_SCREEN_ID) { - FileLog.d(TAG, String.format( - "Skipping item %d, type %d not on a valid screen %d", - id, type, screen)); - continue; - } - if (firstScreenId == null) { - firstScreenId = screen; - } - // Reset the screen to 0-index value - if (createEmptyRowOnFirstScreen && firstScreenId.equals(screen)) { - // Shift items by 1. - cellY++; - // Change the screen id to first screen - screen = Workspace.FIRST_SCREEN_ID; - } - - mMaxGridSizeX = Math.max(mMaxGridSizeX, cellX + spanX); - mMaxGridSizeY = Math.max(mMaxGridSizeY, cellY + spanY); - break; - } - case Favorites.CONTAINER_HOTSEAT: { - mHotseatSize = Math.max(mHotseatSize, screen + 1); - break; - } - default: - if (!mValidFolders.get(container)) { - FileLog.d(TAG, String.format("Skipping item %d, type %d not in a valid folder %d", id, type, container)); - continue; - } - } - - Intent intent = null; - switch (type) { - case Favorites.ITEM_TYPE_FOLDER: { - mValidFolders.put(id, true); - // Use a empty intent to indicate a folder. - intent = new Intent(); - break; - } - case Favorites.ITEM_TYPE_APPWIDGET: { - values.put(Favorites.RESTORED, - LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | - LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY | - LauncherAppWidgetInfo.FLAG_UI_NOT_READY); - values.put(Favorites.APPWIDGET_PROVIDER, c.getString(widgetProviderIndex)); - break; - } - case Favorites.ITEM_TYPE_SHORTCUT: - case Favorites.ITEM_TYPE_APPLICATION: { - intent = Intent.parseUri(c.getString(intentIndex), 0); - if (PackageManagerHelper.isLauncherAppTarget(intent)) { - type = Favorites.ITEM_TYPE_APPLICATION; - } else { - values.put(Favorites.ICON_PACKAGE, c.getString(iconPackageIndex)); - values.put(Favorites.ICON_RESOURCE, c.getString(iconResourceIndex)); - } - values.put(Favorites.ICON, c.getBlob(iconIndex)); - values.put(Favorites.INTENT, intent.toUri(0)); - values.put(Favorites.RANK, c.getInt(rankIndex)); - - values.put(Favorites.RESTORED, 1); - break; - } - default: - FileLog.d(TAG, String.format("Skipping item %d, not a valid type %d", id, type)); - continue; - } - - if (container == Favorites.CONTAINER_HOTSEAT) { - if (intent == null) { - FileLog.d(TAG, String.format("Skipping item %d, null intent on hotseat", id)); - continue; - } - if (intent.getComponent() != null) { - intent.setPackage(intent.getComponent().getPackageName()); - } - hotseatTargetApps.add(getPackage(intent)); - } - - values.put(Favorites._ID, id); - values.put(Favorites.ITEM_TYPE, type); - values.put(Favorites.CONTAINER, container); - values.put(Favorites.SCREEN, screen); - values.put(Favorites.CELLX, cellX); - values.put(Favorites.CELLY, cellY); - values.put(Favorites.SPANX, spanX); - values.put(Favorites.SPANY, spanY); - values.put(Favorites.TITLE, c.getString(titleIndex)); - insertOperations.add(ContentProviderOperation - .newInsert(Favorites.CONTENT_URI).withValues(values).build()); - if (container < 0) { - totalItemsOnWorkspace++; - } - - if (insertOperations.size() >= BATCH_INSERT_SIZE) { - mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, - insertOperations); - insertOperations.clear(); - } - } - } - FileLog.d(TAG, totalItemsOnWorkspace + " items imported from external source"); - if (totalItemsOnWorkspace < MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION) { - throw new Exception("Insufficient data"); - } - if (!insertOperations.isEmpty()) { - mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, - insertOperations); - insertOperations.clear(); - } - - IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask - .removeBrokenHotseatItems(mContext); - int myHotseatCount = LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons; - if (hotseatItems.size() < myHotseatCount) { - // Insufficient hotseat items. Add a few more. - HotseatParserCallback parserCallback = new HotseatParserCallback( - hotseatTargetApps, hotseatItems, insertOperations, maxId + 1, myHotseatCount); - new HotseatLayoutParser(mContext, - parserCallback).loadLayout(null, new IntArray()); - mHotseatSize = hotseatItems.keyAt(hotseatItems.size() - 1) + 1; - - if (!insertOperations.isEmpty()) { - mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, - insertOperations); - } - } - } - - private static String getPackage(Intent intent) { - return intent.getComponent() != null ? intent.getComponent().getPackageName() - : intent.getPackage(); - } - - /** - * Performs data import if possible. - * @return true on successful data import, false if it was not available - * @throws Exception if the import failed - */ - public static boolean performImportIfPossible(Context context) throws Exception { - SharedPreferences devicePrefs = getDevicePrefs(context); - String sourcePackage = devicePrefs.getString(KEY_DATA_IMPORT_SRC_PKG, ""); - String sourceAuthority = devicePrefs.getString(KEY_DATA_IMPORT_SRC_AUTHORITY, ""); - - if (TextUtils.isEmpty(sourcePackage) || TextUtils.isEmpty(sourceAuthority)) { - return false; - } - - // Synchronously clear the migration flags. This ensures that we do not try migration - // again and thus prevents potential crash loops due to migration failure. - devicePrefs.edit().remove(KEY_DATA_IMPORT_SRC_PKG).remove(KEY_DATA_IMPORT_SRC_AUTHORITY).commit(); - - if (!Settings.call(context.getContentResolver(), Settings.METHOD_WAS_EMPTY_DB_CREATED) - .getBoolean(Settings.EXTRA_VALUE, false)) { - // Only migration if a new DB was created. - return false; - } - - for (ProviderInfo info : context.getPackageManager().queryContentProviders( - null, context.getApplicationInfo().uid, 0)) { - - if (sourcePackage.equals(info.packageName)) { - if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - // Only migrate if the source launcher is also on system image. - return false; - } - - // Wait until we found a provider with matching authority. - if (sourceAuthority.equals(info.authority)) { - if (TextUtils.isEmpty(info.readPermission) || - context.checkPermission(info.readPermission, Process.myPid(), - Process.myUid()) == PackageManager.PERMISSION_GRANTED) { - // All checks passed, run the import task. - return new ImportDataTask(context, sourceAuthority).importWorkspace(); - } - } - } - } - return false; - } - - /** - * Extension of {@link DefaultLayoutParser} which only allows icons and shortcuts. - */ - private static class HotseatLayoutParser extends DefaultLayoutParser { - public HotseatLayoutParser(Context context, LayoutParserCallback callback) { - super(context, null, callback, context.getResources(), - LauncherAppState.getIDP(context).defaultLayoutId); - } - - @Override - protected ArrayMap<String, TagParser> getLayoutElementsMap() { - // Only allow shortcut parsers - ArrayMap<String, TagParser> parsers = new ArrayMap<>(); - parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser()); - parsers.put(TAG_SHORTCUT, new UriShortcutParser(mSourceRes)); - parsers.put(TAG_RESOLVE, new ResolveParser()); - return parsers; - } - } - - /** - * {@link LayoutParserCallback} which adds items in empty hotseat spots. - */ - private static class HotseatParserCallback implements LayoutParserCallback { - private final HashSet<String> mExistingApps; - private final IntSparseArrayMap<Object> mExistingItems; - private final ArrayList<ContentProviderOperation> mOutOps; - private final int mRequiredSize; - private int mStartItemId; - - HotseatParserCallback( - HashSet<String> existingApps, IntSparseArrayMap<Object> existingItems, - ArrayList<ContentProviderOperation> outOps, int startItemId, int requiredSize) { - mExistingApps = existingApps; - mExistingItems = existingItems; - mOutOps = outOps; - mRequiredSize = requiredSize; - mStartItemId = startItemId; - } - - @Override - public int generateNewItemId() { - return mStartItemId++; - } - - @Override - public int insertAndCheck(SQLiteDatabase db, ContentValues values) { - if (mExistingItems.size() >= mRequiredSize) { - // No need to add more items. - return 0; - } - if (!Integer.valueOf(Favorites.CONTAINER_HOTSEAT) - .equals(values.getAsInteger(Favorites.CONTAINER))) { - // Ignore items which are not for hotseat. - return 0; - } - - Intent intent; - try { - intent = Intent.parseUri(values.getAsString(Favorites.INTENT), 0); - } catch (URISyntaxException e) { - return 0; - } - String pkg = getPackage(intent); - if (pkg == null || mExistingApps.contains(pkg)) { - // The item does not target an app or is already in hotseat. - return 0; - } - mExistingApps.add(pkg); - - // find next vacant spot. - int screen = 0; - while (mExistingItems.get(screen) != null) { - screen++; - } - mExistingItems.put(screen, intent); - values.put(Favorites.SCREEN, screen); - mOutOps.add(ContentProviderOperation.newInsert(Favorites.CONTENT_URI).withValues(values).build()); - return 0; - } - } -} |