use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class ImportDataTask method importWorkspaceItems.
/**
* 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(UserManagerCompat.getInstance(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 }, // 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).numHotseatIcons;
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);
}
}
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class GridSizeMigrationTask method migrateWorkspace.
/**
* @return true if any DB change was made
*/
protected boolean migrateWorkspace() throws Exception {
IntArray allScreens = getWorkspaceScreenIds(mDb);
if (allScreens.isEmpty()) {
throw new Exception("Unable to get workspace screens");
}
for (int i = 0; i < allScreens.size(); i++) {
int screenId = allScreens.get(i);
if (DEBUG) {
Log.d(TAG, "Migrating " + screenId);
}
migrateScreen(screenId);
}
if (!mCarryOver.isEmpty()) {
IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
for (DbEntry e : mCarryOver) {
itemMap.put(e.id, e);
}
do {
// Some items are still remaining. Try adding a few new screens.
// At every iteration, make sure that at least one item is removed from
// {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed,
// break the loop and abort migration by throwing an exception.
OptimalPlacementSolution placement = new OptimalPlacementSolution(new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true);
placement.find();
if (placement.finalPlacedItems.size() > 0) {
int newScreenId = LauncherSettings.Settings.call(mContext.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_SCREEN_ID).getInt(EXTRA_VALUE);
for (DbEntry item : placement.finalPlacedItems) {
if (!mCarryOver.remove(itemMap.get(item.id))) {
throw new Exception("Unable to find matching items");
}
item.screenId = newScreenId;
update(item);
}
} else {
throw new Exception("None of the items can be placed on an empty screen");
}
} while (!mCarryOver.isEmpty());
}
return applyOperations();
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class GridSizeMigrationTask method removeBrokenHotseatItems.
/**
* Removes any broken item from the hotseat.
*
* @return a map with occupied hotseat position set to non-null value.
*/
public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception {
try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call(context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION).getBinder(Settings.EXTRA_VALUE)) {
GridSizeMigrationTask task = new GridSizeMigrationTask(context, transaction.getDb(), getValidPackages(context), Integer.MAX_VALUE, Integer.MAX_VALUE);
// Load all the valid entries
ArrayList<DbEntry> items = task.loadHotseatEntries();
// Delete any entry marked for deletion by above load.
task.applyOperations();
IntSparseArrayMap<Object> positions = new IntSparseArrayMap<>();
for (DbEntry item : items) {
positions.put(item.screenId, item);
}
transaction.commit();
return positions;
}
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class GridSizeMigrationTask method migrateScreen.
/**
* Migrate a particular screen id.
* Strategy:
* 1) For all possible combinations of row and column, pick the one which causes the least
* data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
* 2) Maintain a list of all lost items before this screen, and add any new item lost from
* this screen to that list as well.
* 3) If all those items from the above list can be placed on this screen, place them
* (otherwise they are placed on a new screen).
*/
protected void migrateScreen(int screenId) {
// If we are migrating the first screen, do not touch the first row.
int startY = (FeatureFlags.QSB_ON_FIRST_SCREEN && screenId == Workspace.FIRST_SCREEN_ID) ? 1 : 0;
ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
int removedCol = Integer.MAX_VALUE;
int removedRow = Integer.MAX_VALUE;
// removeWt represents the cost function for loss of items during migration, and moveWt
// represents the cost function for repositioning the items. moveWt is only considered if
// removeWt is same for two different configurations.
// Start with Float.MAX_VALUE (assuming full data) and pick the configuration with least
// cost.
float removeWt = Float.MAX_VALUE;
float moveWt = Float.MAX_VALUE;
float[] outLoss = new float[2];
ArrayList<DbEntry> finalItems = null;
// Try removing all possible combinations
for (int x = 0; x < mSrcX; x++) {
// nicely aligned with hotseat.
for (int y = mSrcY - 1; y >= startY; y--) {
// Use a deep copy when trying out a particular combination as it can change
// the underlying object.
ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss);
if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) {
removeWt = outLoss[0];
moveWt = outLoss[1];
removedCol = mShouldRemoveX ? x : removedCol;
removedRow = mShouldRemoveY ? y : removedRow;
finalItems = itemsOnScreen;
}
// No need to loop over all rows, if a row removal is not needed.
if (!mShouldRemoveY) {
break;
}
}
if (!mShouldRemoveX) {
break;
}
}
if (DEBUG) {
Log.d(TAG, String.format("Removing row %d, column %d on screen %d", removedRow, removedCol, screenId));
}
IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
for (DbEntry e : deepCopy(items)) {
itemMap.put(e.id, e);
}
for (DbEntry item : finalItems) {
DbEntry org = itemMap.get(item.id);
itemMap.remove(item.id);
// Check if update is required
if (!item.columnsSame(org)) {
update(item);
}
}
// The remaining items in {@link #itemMap} are those which didn't get placed.
for (DbEntry item : itemMap) {
mCarryOver.add(item);
}
if (!mCarryOver.isEmpty() && removeWt == 0) {
// No new items were removed in this step. Try placing all the items on this screen.
GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
occupied.markCells(0, 0, mTrgX, startY, true);
for (DbEntry item : finalItems) {
occupied.markCells(item, true);
}
OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, deepCopy(mCarryOver), startY, true);
placement.find();
if (placement.lowestWeightLoss == 0) {
for (DbEntry item : placement.finalPlacedItems) {
item.screenId = screenId;
update(item);
}
mCarryOver.clear();
}
}
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class BgDataModel method dumpProto.
private synchronized void dumpProto(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
// Add top parent nodes. (L1)
DumpTargetWrapper hotseat = new DumpTargetWrapper(ContainerType.HOTSEAT, 0);
IntSparseArrayMap<DumpTargetWrapper> workspaces = new IntSparseArrayMap<>();
IntArray workspaceScreens = collectWorkspaceScreens();
for (int i = 0; i < workspaceScreens.size(); i++) {
workspaces.put(workspaceScreens.get(i), new DumpTargetWrapper(ContainerType.WORKSPACE, i));
}
DumpTargetWrapper dtw;
// Add non leaf / non top nodes (L2)
for (int i = 0; i < folders.size(); i++) {
FolderInfo fInfo = folders.valueAt(i);
dtw = new DumpTargetWrapper(ContainerType.FOLDER, folders.size());
dtw.writeToDumpTarget(fInfo);
for (WorkspaceItemInfo sInfo : fInfo.contents) {
DumpTargetWrapper child = new DumpTargetWrapper(sInfo);
child.writeToDumpTarget(sInfo);
dtw.add(child);
}
if (fInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
hotseat.add(dtw);
} else if (fInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
workspaces.get(fInfo.screenId).add(dtw);
}
}
// Add leaf nodes (L3): *Info
for (int i = 0; i < workspaceItems.size(); i++) {
ItemInfo info = workspaceItems.get(i);
if (info instanceof FolderInfo) {
continue;
}
dtw = new DumpTargetWrapper(info);
dtw.writeToDumpTarget(info);
if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
hotseat.add(dtw);
} else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
workspaces.get(info.screenId).add(dtw);
}
}
for (int i = 0; i < appWidgets.size(); i++) {
ItemInfo info = appWidgets.get(i);
dtw = new DumpTargetWrapper(info);
dtw.writeToDumpTarget(info);
if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
hotseat.add(dtw);
} else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
workspaces.get(info.screenId).add(dtw);
}
}
// Traverse target wrapper
ArrayList<DumpTarget> targetList = new ArrayList<>();
targetList.addAll(hotseat.getFlattenedList());
for (int i = 0; i < workspaces.size(); i++) {
targetList.addAll(workspaces.valueAt(i).getFlattenedList());
}
if (Arrays.asList(args).contains("--debug")) {
for (int i = 0; i < targetList.size(); i++) {
writer.println(prefix + DumpTargetWrapper.getDumpTargetStr(targetList.get(i)));
}
return;
} else {
LauncherDumpProto.LauncherImpression proto = new LauncherDumpProto.LauncherImpression();
proto.targets = new DumpTarget[targetList.size()];
for (int i = 0; i < targetList.size(); i++) {
proto.targets[i] = targetList.get(i);
}
FileOutputStream fos = new FileOutputStream(fd);
try {
fos.write(MessageNano.toByteArray(proto));
Log.d(TAG, MessageNano.toByteArray(proto).length + "Bytes");
} catch (IOException e) {
Log.e(TAG, "Exception writing dumpsys --proto", e);
}
}
}
Aggregations