summaryrefslogtreecommitdiff
path: root/src/com/android/launcher3/provider/ImportDataTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/provider/ImportDataTask.java')
-rw-r--r--src/com/android/launcher3/provider/ImportDataTask.java438
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;
- }
- }
-}