Merge "Adding accessibility controls" into ub-launcher3-almonte
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
android:id="@+id/delete_target_text"
|
||||
style="@style/DropTargetButton"
|
||||
android:drawableStart="@drawable/remove_target_selector"
|
||||
android:text="@string/delete_zone_label_workspace" />
|
||||
android:text="@string/delete_target_label" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
|
||||
@@ -4,8 +4,4 @@
|
||||
|
||||
<!-- DragController -->
|
||||
<integer name="config_flingToDeleteMinVelocity">-1000</integer>
|
||||
|
||||
<!-- Camera distance for the overscroll effect. We use a higher value here because the
|
||||
workspace screens run nearly flush to the edge of the screen-->
|
||||
<integer name="config_cameraDistance">14000</integer>
|
||||
</resources>
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
<!-- Whether or not the drop targets drop down as opposed to fade in -->
|
||||
<bool name="config_useDropTargetDownTransition">false</bool>
|
||||
|
||||
<!-- Camera distance for the overscroll effect -->
|
||||
<integer name="config_cameraDistance">18000</integer>
|
||||
|
||||
<!-- Hotseat -->
|
||||
<bool name="hotseat_transpose_layout_with_orientation">false</bool>
|
||||
</resources>
|
||||
|
||||
@@ -36,11 +36,6 @@
|
||||
<!-- Fade/zoom in/out duration & scale in the AllApps transition.
|
||||
Note: This should be less than the workspaceShrinkTime as they happen together. -->
|
||||
<integer name="config_appsCustomizeRevealTime">220</integer>
|
||||
<integer name="config_appsCustomizeZoomInTime">350</integer>
|
||||
<integer name="config_appsCustomizeZoomOutTime">600</integer>
|
||||
<integer name="config_appsCustomizeZoomScaleFactor">7</integer>
|
||||
<integer name="config_appsCustomizeFadeInTime">250</integer>
|
||||
<integer name="config_appsCustomizeFadeOutTime">200</integer>
|
||||
<integer name="config_appsCustomizeWorkspaceShrinkTime">300</integer>
|
||||
|
||||
<integer name="config_appsCustomizeConcealTime">250</integer>
|
||||
@@ -90,9 +85,6 @@
|
||||
<integer name="config_dragFadeOutAlpha">80</integer>
|
||||
<integer name="config_dragFadeOutDuration">250</integer>
|
||||
|
||||
<!-- Camera distance for the overscroll effect -->
|
||||
<integer name="config_cameraDistance">8000</integer>
|
||||
|
||||
<!-- Hotseat -->
|
||||
<bool name="hotseat_transpose_layout_with_orientation">true</bool>
|
||||
|
||||
@@ -106,4 +98,10 @@
|
||||
<!-- Name of a subclass of com.android.launcher3.BuildInfo used to
|
||||
get build information. Can be empty. -->
|
||||
<string name="build_info_class" translatable="false"></string>
|
||||
|
||||
<!-- Accessibility actions -->
|
||||
<item type="id" name="action_remove" />
|
||||
<item type="id" name="action_uninstall" />
|
||||
<item type="id" name="action_info" />
|
||||
<item type="id" name="action_add_to_workspace" />
|
||||
</resources>
|
||||
|
||||
@@ -118,9 +118,6 @@ s -->
|
||||
<!-- Label for button in all applications label to go back home (to the workspace / desktop)
|
||||
for accessibilty (spoken when the button gets focus). -->
|
||||
<string name="all_apps_home_button_label">Home</string>
|
||||
<!-- Label for trash icon on workspace. Meant to communicate the idea of removing the
|
||||
icon/widget from the home screen, but not permanently. [CHAR_LIMIT=30] -->
|
||||
<string name="delete_zone_label_workspace">Remove</string>
|
||||
<!-- Label for trash icon in All Apps. The icon/widget will become completely unavailable on the
|
||||
device. [CHAR_LIMIT=30]-->
|
||||
<string name="delete_zone_label_all_apps">Uninstall</string>
|
||||
@@ -304,4 +301,8 @@ s -->
|
||||
<string name="abandoned_promise_explanation">The app for this icon isn\'t installed.
|
||||
You can remove it, or search for the app and install it manually.
|
||||
</string>
|
||||
|
||||
<!-- Strings for accessibility actions -->
|
||||
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] -->
|
||||
<string name="action_add_to_workspace">Add To Workspace</string>
|
||||
</resources>
|
||||
|
||||
@@ -49,7 +49,15 @@ public class BubbleTextView extends TextView {
|
||||
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
|
||||
static final float PADDING_V = 3.0f;
|
||||
|
||||
private HolographicOutlineHelper mOutlineHelper;
|
||||
|
||||
private final Drawable mBackground;
|
||||
private final CheckLongPressHelper mLongPressHelper;
|
||||
private final HolographicOutlineHelper mOutlineHelper;
|
||||
|
||||
// TODO: Remove custom background handling code, as no instance of BubbleTextView use any
|
||||
// background.
|
||||
private boolean mBackgroundSizeChanged;
|
||||
|
||||
private Bitmap mPressedBackground;
|
||||
|
||||
private float mSlop;
|
||||
@@ -58,14 +66,8 @@ public class BubbleTextView extends TextView {
|
||||
private final boolean mCustomShadowsEnabled;
|
||||
private boolean mIsTextVisible;
|
||||
|
||||
// TODO: Remove custom background handling code, as no instance of BubbleTextView use any
|
||||
// background.
|
||||
private boolean mBackgroundSizeChanged;
|
||||
private final Drawable mBackground;
|
||||
|
||||
private boolean mStayPressed;
|
||||
private boolean mIgnorePressedStateChange;
|
||||
private CheckLongPressHelper mLongPressHelper;
|
||||
|
||||
public BubbleTextView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -90,7 +92,14 @@ public class BubbleTextView extends TextView {
|
||||
} else {
|
||||
mBackground = null;
|
||||
}
|
||||
init();
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
|
||||
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
|
||||
if (mCustomShadowsEnabled) {
|
||||
setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
|
||||
}
|
||||
|
||||
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
public void onFinishInflate() {
|
||||
@@ -102,15 +111,6 @@ public class BubbleTextView extends TextView {
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
|
||||
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
|
||||
if (mCustomShadowsEnabled) {
|
||||
setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
||||
boolean setDefaultPadding) {
|
||||
applyFromShortcutInfo(info, iconCache, setDefaultPadding, false);
|
||||
@@ -328,7 +328,7 @@ public class BubbleTextView extends TextView {
|
||||
Drawable top = getCompoundDrawables()[1];
|
||||
|
||||
if (top instanceof PreloadIconDrawable) {
|
||||
((PreloadIconDrawable) top).applyTheme(getPreloaderTheme());
|
||||
((PreloadIconDrawable) top).applyPreloaderTheme(getPreloaderTheme());
|
||||
}
|
||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
}
|
||||
|
||||
@@ -2981,11 +2981,11 @@ public class CellLayout extends ViewGroup {
|
||||
static boolean findVacantCell(int[] vacant, int spanX, int spanY,
|
||||
int xCount, int yCount, boolean[][] occupied) {
|
||||
|
||||
for (int y = 0; y < yCount; y++) {
|
||||
for (int x = 0; x < xCount; x++) {
|
||||
for (int y = 0; (y + spanY) <= yCount; y++) {
|
||||
for (int x = 0; (x + spanX) <= xCount; x++) {
|
||||
boolean available = !occupied[x][y];
|
||||
out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
|
||||
for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
|
||||
out: for (int i = x; i < x + spanX; i++) {
|
||||
for (int j = y; j < y + spanY; j++) {
|
||||
available = available && !occupied[i][j];
|
||||
if (!available) break out;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.launcher3;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
@@ -115,15 +116,6 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
private boolean isDragSourceWorkspaceOrFolder(DragObject d) {
|
||||
return (d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder);
|
||||
}
|
||||
private boolean isWorkspaceOrFolderApplication(DragObject d) {
|
||||
return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo);
|
||||
}
|
||||
private boolean isWorkspaceOrFolderWidget(DragObject d) {
|
||||
return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof LauncherAppWidgetInfo);
|
||||
}
|
||||
private boolean isWorkspaceFolder(DragObject d) {
|
||||
return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof FolderInfo);
|
||||
}
|
||||
|
||||
private void setHoverColor() {
|
||||
if (mCurrentDrawable != null) {
|
||||
@@ -177,6 +169,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
@Override
|
||||
public void onDragStart(DragSource source, Object info, int dragAction) {
|
||||
boolean isVisible = true;
|
||||
@@ -284,7 +277,8 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
}
|
||||
|
||||
private boolean isUninstallFromWorkspace(DragObject d) {
|
||||
if (LauncherAppState.isDisableAllApps() && isWorkspaceOrFolderApplication(d)) {
|
||||
if (LauncherAppState.isDisableAllApps() && isDragSourceWorkspaceOrFolder(d)
|
||||
&& (d.dragInfo instanceof ShortcutInfo)) {
|
||||
ShortcutInfo shortcut = (ShortcutInfo) d.dragInfo;
|
||||
// Only allow manifest shortcuts to initiate an un-install.
|
||||
return !InstallShortcutReceiver.isValidShortcutLaunchIntent(shortcut.intent);
|
||||
@@ -297,10 +291,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
boolean wasWaitingForUninstall = mWaitingForUninstall;
|
||||
mWaitingForUninstall = false;
|
||||
if (isAllAppsApplication(d.dragSource, item)) {
|
||||
// Uninstall the application if it is being dragged from AppsCustomize
|
||||
AppInfo appInfo = (AppInfo) item;
|
||||
mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags,
|
||||
appInfo.user);
|
||||
uninstallApp(mLauncher, (AppInfo) item);
|
||||
} else if (isUninstallFromWorkspace(d)) {
|
||||
ShortcutInfo shortcut = (ShortcutInfo) item;
|
||||
if (shortcut.intent != null && shortcut.intent.getComponent() != null) {
|
||||
@@ -329,32 +320,8 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess);
|
||||
}
|
||||
}
|
||||
} else if (isWorkspaceOrFolderApplication(d)) {
|
||||
LauncherModel.deleteItemFromDatabase(mLauncher, item);
|
||||
} else if (isWorkspaceFolder(d)) {
|
||||
// Remove the folder from the workspace and delete the contents from launcher model
|
||||
FolderInfo folderInfo = (FolderInfo) item;
|
||||
mLauncher.removeFolder(folderInfo);
|
||||
LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
|
||||
} else if (isWorkspaceOrFolderWidget(d)) {
|
||||
// Remove the widget from the workspace
|
||||
mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
|
||||
LauncherModel.deleteItemFromDatabase(mLauncher, item);
|
||||
|
||||
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
|
||||
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
|
||||
|
||||
if (appWidgetHost != null && !launcherAppWidgetInfo.isCustomWidget()
|
||||
&& launcherAppWidgetInfo.isWidgetIdValid()) {
|
||||
// Deleting an app widget ID is a void call but writes to disk before returning
|
||||
// to the caller...
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
public Void doInBackground(Void ... args) {
|
||||
appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
} else if (isDragSourceWorkspaceOrFolder(d)) {
|
||||
removeWorkspaceOrFolderItem(mLauncher, item, null);
|
||||
}
|
||||
if (wasWaitingForUninstall && !mWaitingForUninstall) {
|
||||
if (d.dragSource instanceof Folder) {
|
||||
@@ -365,6 +332,52 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
}
|
||||
}
|
||||
|
||||
public static void uninstallApp(Launcher launcher, AppInfo info) {
|
||||
launcher.startApplicationUninstallActivity(info.componentName, info.flags, info.user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the item from the workspace. If the view is not null, it also removes the view.
|
||||
* @return true if the item was removed.
|
||||
*/
|
||||
public static boolean removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) {
|
||||
if (item instanceof ShortcutInfo) {
|
||||
LauncherModel.deleteItemFromDatabase(launcher, item);
|
||||
} else if (item instanceof FolderInfo) {
|
||||
FolderInfo folder = (FolderInfo) item;
|
||||
launcher.removeFolder(folder);
|
||||
LauncherModel.deleteFolderContentsFromDatabase(launcher, folder);
|
||||
} else if (item instanceof LauncherAppWidgetInfo) {
|
||||
final LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) item;
|
||||
|
||||
// Remove the widget from the workspace
|
||||
launcher.removeAppWidget(widget);
|
||||
LauncherModel.deleteItemFromDatabase(launcher, widget);
|
||||
|
||||
final LauncherAppWidgetHost appWidgetHost = launcher.getAppWidgetHost();
|
||||
|
||||
if (appWidgetHost != null && !widget.isCustomWidget()
|
||||
&& widget.isWidgetIdValid()) {
|
||||
// Deleting an app widget ID is a void call but writes to disk before returning
|
||||
// to the caller...
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
public Void doInBackground(Void ... args) {
|
||||
appWidgetHost.deleteAppWidgetId(widget.appWidgetId);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (view != null) {
|
||||
launcher.getWorkspace().removeWorkspaceItem(view);
|
||||
launcher.getWorkspace().stripEmptyScreens();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onDrop(DragObject d) {
|
||||
animateToTrashAndCompleteDrop(d);
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
|
||||
private void init() {
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
public boolean isDropEnabled() {
|
||||
|
||||
@@ -76,28 +76,32 @@ public class InfoDropTarget extends ButtonDropTarget {
|
||||
// acceptDrop is called just before onDrop. We do the work here, rather than
|
||||
// in onDrop, because it allows us to reject the drop (by returning false)
|
||||
// so that the object being dragged isn't removed from the drag source.
|
||||
|
||||
startDetailsActivityForInfo(d.dragInfo, mLauncher);
|
||||
// There is no post-drop animation, so clean up the DragView now
|
||||
d.deferDragViewCleanupPostAnimation = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void startDetailsActivityForInfo(Object info, Launcher launcher) {
|
||||
ComponentName componentName = null;
|
||||
if (d.dragInfo instanceof AppInfo) {
|
||||
componentName = ((AppInfo) d.dragInfo).componentName;
|
||||
} else if (d.dragInfo instanceof ShortcutInfo) {
|
||||
componentName = ((ShortcutInfo) d.dragInfo).intent.getComponent();
|
||||
} else if (d.dragInfo instanceof PendingAddItemInfo) {
|
||||
componentName = ((PendingAddItemInfo) d.dragInfo).componentName;
|
||||
if (info instanceof AppInfo) {
|
||||
componentName = ((AppInfo) info).componentName;
|
||||
} else if (info instanceof ShortcutInfo) {
|
||||
componentName = ((ShortcutInfo) info).intent.getComponent();
|
||||
} else if (info instanceof PendingAddItemInfo) {
|
||||
componentName = ((PendingAddItemInfo) info).componentName;
|
||||
}
|
||||
final UserHandleCompat user;
|
||||
if (d.dragInfo instanceof ItemInfo) {
|
||||
user = ((ItemInfo) d.dragInfo).user;
|
||||
if (info instanceof ItemInfo) {
|
||||
user = ((ItemInfo) info).user;
|
||||
} else {
|
||||
user = UserHandleCompat.myUserHandle();
|
||||
}
|
||||
|
||||
if (componentName != null) {
|
||||
mLauncher.startApplicationDetailsActivity(componentName, user);
|
||||
launcher.startApplicationDetailsActivity(componentName, user);
|
||||
}
|
||||
|
||||
// There is no post-drop animation, so clean up the DragView now
|
||||
d.deferDragViewCleanupPostAnimation = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -162,7 +162,6 @@ public class Launcher extends Activity
|
||||
static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
|
||||
|
||||
static final int SCREEN_COUNT = 5;
|
||||
static final int DEFAULT_SCREEN = 2;
|
||||
|
||||
// To turn on these properties, type
|
||||
// adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
|
||||
@@ -232,7 +231,6 @@ public class Launcher extends Activity
|
||||
private static final int ACTIVITY_START_DELAY = 1000;
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
private static int sScreen = DEFAULT_SCREEN;
|
||||
|
||||
private HashMap<Integer, Integer> mItemIdToViewId = new HashMap<Integer, Integer>();
|
||||
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
|
||||
@@ -675,18 +673,7 @@ public class Launcher extends Activity
|
||||
return !mModel.isLoadingWorkspace();
|
||||
}
|
||||
|
||||
static int getScreen() {
|
||||
synchronized (sLock) {
|
||||
return sScreen;
|
||||
}
|
||||
}
|
||||
|
||||
static void setScreen(int screen) {
|
||||
synchronized (sLock) {
|
||||
sScreen = screen;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
public static int generateViewId() {
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
return View.generateViewId();
|
||||
@@ -1594,7 +1581,6 @@ public class Launcher extends Activity
|
||||
* Add a widget to the workspace.
|
||||
*
|
||||
* @param appWidgetId The app widget id
|
||||
* @param cellInfo The position on screen where to create the widget.
|
||||
*/
|
||||
private void completeAddAppWidget(int appWidgetId, long container, long screenId,
|
||||
AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
|
||||
@@ -2294,20 +2280,39 @@ public class Launcher extends Activity
|
||||
closeFolder();
|
||||
mWorkspace.moveToCustomContentScreen(animate);
|
||||
}
|
||||
|
||||
public void addPendingItem(PendingAddItemInfo info, long container, long screenId,
|
||||
int[] cell, int spanX, int spanY) {
|
||||
switch (info.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
|
||||
int span[] = new int[2];
|
||||
span[0] = spanX;
|
||||
span[1] = spanY;
|
||||
addAppWidgetFromDrop((PendingAddWidgetInfo) info,
|
||||
container, screenId, cell, span);
|
||||
break;
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
processShortcutFromDrop(info.componentName, container, screenId, cell);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown item type: " + info.itemType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a shortcut drop.
|
||||
*
|
||||
* @param componentName The name of the component
|
||||
* @param screenId The ID of the screen where it should be added
|
||||
* @param cell The cell it should be added to, optional
|
||||
* @param position The location on the screen where it was dropped, optional
|
||||
*/
|
||||
void processShortcutFromDrop(ComponentName componentName, long container, long screenId,
|
||||
int[] cell, int[] loc) {
|
||||
private void processShortcutFromDrop(ComponentName componentName, long container, long screenId,
|
||||
int[] cell) {
|
||||
resetAddInfo();
|
||||
mPendingAddInfo.container = container;
|
||||
mPendingAddInfo.screenId = screenId;
|
||||
mPendingAddInfo.dropPos = loc;
|
||||
mPendingAddInfo.dropPos = null;
|
||||
|
||||
if (cell != null) {
|
||||
mPendingAddInfo.cellX = cell[0];
|
||||
@@ -2325,14 +2330,13 @@ public class Launcher extends Activity
|
||||
* @param info The PendingAppWidgetInfo of the widget being added.
|
||||
* @param screenId The ID of the screen where it should be added
|
||||
* @param cell The cell it should be added to, optional
|
||||
* @param position The location on the screen where it was dropped, optional
|
||||
*/
|
||||
void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, long screenId,
|
||||
int[] cell, int[] span, int[] loc) {
|
||||
private void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, long screenId,
|
||||
int[] cell, int[] span) {
|
||||
resetAddInfo();
|
||||
mPendingAddInfo.container = info.container = container;
|
||||
mPendingAddInfo.screenId = info.screenId = screenId;
|
||||
mPendingAddInfo.dropPos = loc;
|
||||
mPendingAddInfo.dropPos = null;
|
||||
mPendingAddInfo.minSpanX = info.minSpanX;
|
||||
mPendingAddInfo.minSpanY = info.minSpanY;
|
||||
|
||||
@@ -3291,6 +3295,7 @@ public class Launcher extends Activity
|
||||
showAppsCustomizeHelper(animated, springLoaded, contentType);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded,
|
||||
final AppsCustomizePagedView.ContentType contentType) {
|
||||
if (mStateAnimation != null) {
|
||||
@@ -3303,13 +3308,10 @@ public class Launcher extends Activity
|
||||
|
||||
final Resources res = getResources();
|
||||
|
||||
final int duration = res.getInteger(R.integer.config_appsCustomizeZoomInTime);
|
||||
final int fadeDuration = res.getInteger(R.integer.config_appsCustomizeFadeInTime);
|
||||
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
|
||||
final int itemsAlphaStagger =
|
||||
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
|
||||
|
||||
final float scale = (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
|
||||
final View fromView = mWorkspace;
|
||||
final AppsCustomizeTabHost toView = mAppsCustomizeTabHost;
|
||||
|
||||
@@ -3536,14 +3538,10 @@ public class Launcher extends Activity
|
||||
boolean material = Utilities.isLmpOrAbove();
|
||||
Resources res = getResources();
|
||||
|
||||
final int duration = res.getInteger(R.integer.config_appsCustomizeZoomOutTime);
|
||||
final int fadeOutDuration = res.getInteger(R.integer.config_appsCustomizeFadeOutTime);
|
||||
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeConcealTime);
|
||||
final int itemsAlphaStagger =
|
||||
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
|
||||
|
||||
final float scaleFactor = (float)
|
||||
res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
|
||||
final View fromView = mAppsCustomizeTabHost;
|
||||
final View toView = mWorkspace;
|
||||
Animator workspaceAnim = null;
|
||||
@@ -4139,6 +4137,19 @@ public class Launcher extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindAddPendingItem(final PendingAddItemInfo info, final long container,
|
||||
final long screenId, final int[] cell, final int spanX, final int spanY) {
|
||||
showWorkspace(true, new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mWorkspace.snapToPage(mWorkspace.getPageIndexForScreenId(screenId));
|
||||
addPendingItem(info, container, screenId, cell, spanX, spanY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean shouldShowWeightWatcher() {
|
||||
String spKey = LauncherAppState.getSharedPreferencesKey();
|
||||
SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.View.AccessibilityDelegate;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
|
||||
import com.android.launcher3.LauncherModel.ScreenPosProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
|
||||
|
||||
public static final int REMOVE = R.id.action_remove;
|
||||
public static final int INFO = R.id.action_info;
|
||||
public static final int UNINSTALL = R.id.action_uninstall;
|
||||
public static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
|
||||
|
||||
private final SparseArray<AccessibilityAction> mActions =
|
||||
new SparseArray<AccessibilityAction>();
|
||||
private final Launcher mLauncher;
|
||||
|
||||
public LauncherAccessibilityDelegate(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
|
||||
mActions.put(REMOVE, new AccessibilityAction(REMOVE,
|
||||
launcher.getText(R.string.delete_target_label)));
|
||||
mActions.put(INFO, new AccessibilityAction(INFO,
|
||||
launcher.getText(R.string.info_target_label)));
|
||||
mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL,
|
||||
launcher.getText(R.string.delete_target_uninstall_label)));
|
||||
mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE,
|
||||
launcher.getText(R.string.action_add_to_workspace)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
if (!(host.getTag() instanceof ItemInfo)) return;
|
||||
ItemInfo item = (ItemInfo) host.getTag();
|
||||
|
||||
if ((item instanceof ShortcutInfo)
|
||||
|| (item instanceof LauncherAppWidgetInfo)
|
||||
|| (item instanceof FolderInfo)) {
|
||||
// Workspace shortcut / widget
|
||||
info.addAction(mActions.get(REMOVE));
|
||||
} else if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
|
||||
// App or Widget from customization tray
|
||||
if (item instanceof AppInfo) {
|
||||
info.addAction(mActions.get(UNINSTALL));
|
||||
}
|
||||
info.addAction(mActions.get(INFO));
|
||||
info.addAction(mActions.get(ADD_TO_WORKSPACE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||
if ((host.getTag() instanceof ItemInfo)
|
||||
&& performAction(host, (ItemInfo) host.getTag(), action)) {
|
||||
return true;
|
||||
}
|
||||
return super.performAccessibilityAction(host, action, args);
|
||||
}
|
||||
|
||||
public boolean performAction(View host, ItemInfo item, int action) {
|
||||
if (action == REMOVE) {
|
||||
return DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host);
|
||||
} else if (action == INFO) {
|
||||
InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
|
||||
return true;
|
||||
} else if (action == UNINSTALL) {
|
||||
DeleteDropTarget.uninstallApp(mLauncher, (AppInfo) item);
|
||||
return true;
|
||||
} else if (action == ADD_TO_WORKSPACE) {
|
||||
final int preferredPage = mLauncher.getWorkspace().getCurrentPage();
|
||||
final ScreenPosProvider screenProvider = new ScreenPosProvider() {
|
||||
|
||||
@Override
|
||||
public int getScreenIndex(ArrayList<Long> screenIDs) {
|
||||
return preferredPage;
|
||||
}
|
||||
};
|
||||
if (item instanceof AppInfo) {
|
||||
final ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>();
|
||||
addShortcuts.add(((AppInfo) item).makeShortcut());
|
||||
mLauncher.showWorkspace(true, new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mLauncher.getModel().addAndBindAddedWorkspaceApps(
|
||||
mLauncher, addShortcuts, screenProvider, 0, true);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if (item instanceof PendingAddItemInfo) {
|
||||
mLauncher.getModel().addAndBindPendingItem(
|
||||
mLauncher, (PendingAddItemInfo) item, screenProvider, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -32,10 +32,13 @@ import android.os.Handler;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.View.AccessibilityDelegate;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -62,6 +65,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
||||
private static LauncherAppState INSTANCE;
|
||||
|
||||
private DynamicGrid mDynamicGrid;
|
||||
private AccessibilityDelegate mAccessibilityDelegate;
|
||||
|
||||
public static LauncherAppState getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
@@ -162,9 +166,15 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
||||
|
||||
LauncherModel setLauncher(Launcher launcher) {
|
||||
mModel.initialize(launcher);
|
||||
mAccessibilityDelegate = ((launcher != null) && Utilities.isLmpOrAbove()) ?
|
||||
new LauncherAccessibilityDelegate(launcher) : null;
|
||||
return mModel;
|
||||
}
|
||||
|
||||
AccessibilityDelegate getAccessibilityDelegate() {
|
||||
return mAccessibilityDelegate;
|
||||
}
|
||||
|
||||
public IconCache getIconCache() {
|
||||
return mIconCache;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mDragLayer = ((Launcher) context).getDragLayer();
|
||||
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.content.Intent;
|
||||
import android.content.Intent.ShortcutIconResource;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.LauncherApps.Callback;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
@@ -38,6 +37,7 @@ import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
@@ -49,6 +49,7 @@ import android.os.SystemClock;
|
||||
import android.provider.BaseColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||
@@ -108,7 +109,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
private DeferredHandler mHandler = new DeferredHandler();
|
||||
private LoaderTask mLoaderTask;
|
||||
private boolean mIsLoaderTaskRunning;
|
||||
private volatile boolean mFlushingWorkerThread;
|
||||
|
||||
/**
|
||||
* Maintain a set of packages per user, for which we added a shortcut on the workspace.
|
||||
@@ -219,12 +219,18 @@ public class LauncherModel extends BroadcastReceiver
|
||||
public boolean isAllAppsButtonRank(int rank);
|
||||
public void onPageBoundSynchronously(int page);
|
||||
public void dumpLogsToLocalData();
|
||||
public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,
|
||||
int[] cell, int spanX, int spanY);
|
||||
}
|
||||
|
||||
public interface ItemInfoFilter {
|
||||
public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
|
||||
}
|
||||
|
||||
public interface ScreenPosProvider {
|
||||
int getScreenIndex(ArrayList<Long> screenIDs);
|
||||
}
|
||||
|
||||
LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
|
||||
Context context = app.getContext();
|
||||
|
||||
@@ -287,67 +293,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;
|
||||
}
|
||||
|
||||
static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,
|
||||
long screen) {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
final int xCount = (int) grid.numColumns;
|
||||
final int yCount = (int) grid.numRows;
|
||||
boolean[][] occupied = new boolean[xCount][yCount];
|
||||
|
||||
int cellX, cellY, spanX, spanY;
|
||||
for (int i = 0; i < items.size(); ++i) {
|
||||
final ItemInfo item = items.get(i);
|
||||
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
if (item.screenId == screen) {
|
||||
cellX = item.cellX;
|
||||
cellY = item.cellY;
|
||||
spanX = item.spanX;
|
||||
spanY = item.spanY;
|
||||
for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {
|
||||
for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {
|
||||
occupied[x][y] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);
|
||||
}
|
||||
static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,
|
||||
Intent launchIntent,
|
||||
int firstScreenIndex,
|
||||
ArrayList<Long> workspaceScreens) {
|
||||
// Lock on the app so that we don't try and get the items while apps are being added
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
LauncherModel model = app.getModel();
|
||||
boolean found = false;
|
||||
synchronized (app) {
|
||||
if (sWorkerThread.getThreadId() != Process.myTid()) {
|
||||
// Flush the LauncherModel worker thread, so that if we just did another
|
||||
// processInstallShortcut, we give it time for its shortcut to get added to the
|
||||
// database (getItemsInLocalCoordinates reads the database)
|
||||
model.flushWorkerThread();
|
||||
}
|
||||
final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
|
||||
|
||||
// Try adding to the workspace screens incrementally, starting at the default or center
|
||||
// screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))
|
||||
firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());
|
||||
int count = workspaceScreens.size();
|
||||
for (int screen = firstScreenIndex; screen < count && !found; screen++) {
|
||||
int[] tmpCoordinates = new int[2];
|
||||
if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,
|
||||
workspaceScreens.get(screen))) {
|
||||
// Update the Launcher db
|
||||
return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {
|
||||
// Process the updated package state
|
||||
Runnable r = new Runnable() {
|
||||
@@ -402,11 +347,196 @@ public class LauncherModel extends BroadcastReceiver
|
||||
|
||||
public void addAndBindAddedWorkspaceApps(final Context context,
|
||||
final ArrayList<ItemInfo> workspaceApps) {
|
||||
final Callbacks callbacks = getCallback();
|
||||
addAndBindAddedWorkspaceApps(context, workspaceApps,
|
||||
new ScreenPosProvider() {
|
||||
|
||||
if (workspaceApps == null) {
|
||||
throw new RuntimeException("workspaceApps and allAppsApps must not be null");
|
||||
@Override
|
||||
public int getScreenIndex(ArrayList<Long> screenIDs) {
|
||||
return screenIDs.isEmpty() ? 0 : 1;
|
||||
}
|
||||
}, 1, false);
|
||||
}
|
||||
|
||||
private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,
|
||||
int[] xy, int spanX, int spanY) {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
final int xCount = (int) grid.numColumns;
|
||||
final int yCount = (int) grid.numRows;
|
||||
boolean[][] occupied = new boolean[xCount][yCount];
|
||||
if (occupiedPos != null) {
|
||||
for (Rect r : occupiedPos) {
|
||||
for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {
|
||||
for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {
|
||||
occupied[x][y] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a position on the screen for the given size or adds a new screen.
|
||||
* @return screenId and the coordinates for the item.
|
||||
*/
|
||||
private static Pair<Long, int[]> findSpaceForItem(
|
||||
Context context,
|
||||
ScreenPosProvider preferredScreen,
|
||||
int fallbackStartScreen,
|
||||
ArrayList<Long> workspaceScreens,
|
||||
ArrayList<Long> addedWorkspaceScreensFinal,
|
||||
int spanX, int spanY) {
|
||||
// Load position of items which are on the desktop. We can't use sBgItemsIdMap because
|
||||
// loadWorkspace() may not have been called.
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
|
||||
new String[] {
|
||||
LauncherSettings.Favorites.SCREEN,
|
||||
LauncherSettings.Favorites.CELLX,
|
||||
LauncherSettings.Favorites.CELLY,
|
||||
LauncherSettings.Favorites.SPANX,
|
||||
LauncherSettings.Favorites.SPANY,
|
||||
LauncherSettings.Favorites.CONTAINER
|
||||
},
|
||||
"container=?",
|
||||
new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },
|
||||
null);
|
||||
|
||||
final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
|
||||
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
|
||||
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
|
||||
final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
|
||||
final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
|
||||
LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
Rect rect = new Rect();
|
||||
rect.left = c.getInt(cellXIndex);
|
||||
rect.top = c.getInt(cellYIndex);
|
||||
rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));
|
||||
rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));
|
||||
|
||||
long screenId = c.getInt(screenIndex);
|
||||
ArrayList<Rect> items = screenItems.get(screenId);
|
||||
if (items == null) {
|
||||
items = new ArrayList<Rect>();
|
||||
screenItems.put(screenId, items);
|
||||
}
|
||||
items.add(rect);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
screenItems.clear();
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
// Find appropriate space for the item.
|
||||
long screenId = 0;
|
||||
int[] cordinates = new int[2];
|
||||
boolean found = false;
|
||||
|
||||
int screenCount = workspaceScreens.size();
|
||||
// First check the preferred screen.
|
||||
int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);
|
||||
if (preferredScreenIndex < screenCount) {
|
||||
screenId = workspaceScreens.get(preferredScreenIndex);
|
||||
found = findNextAvailableIconSpaceInScreen(
|
||||
screenItems.get(screenId), cordinates, spanX, spanY);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// Search on any of the screens.
|
||||
for (int screen = fallbackStartScreen; screen < screenCount; screen++) {
|
||||
screenId = workspaceScreens.get(screen);
|
||||
if (findNextAvailableIconSpaceInScreen(
|
||||
screenItems.get(screenId), cordinates, spanX, spanY)) {
|
||||
// We found a space for it
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// Still no position found. Add a new screen to the end.
|
||||
screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();
|
||||
|
||||
// Save the screen id for binding in the workspace
|
||||
workspaceScreens.add(screenId);
|
||||
addedWorkspaceScreensFinal.add(screenId);
|
||||
|
||||
// If we still can't find an empty space, then God help us all!!!
|
||||
if (!findNextAvailableIconSpaceInScreen(
|
||||
screenItems.get(screenId), cordinates, spanX, spanY)) {
|
||||
throw new RuntimeException("Can't find space to add the item");
|
||||
}
|
||||
}
|
||||
return Pair.create(screenId, cordinates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provided items to the workspace.
|
||||
* @param preferredScreen the screen where we should try to add the app first
|
||||
* @param fallbackStartScreen the screen to start search for empty space if
|
||||
* preferredScreen is not available.
|
||||
*/
|
||||
public void addAndBindPendingItem(
|
||||
final Context context,
|
||||
final PendingAddItemInfo addInfo,
|
||||
final ScreenPosProvider preferredScreen,
|
||||
final int fallbackStartScreen) {
|
||||
final Callbacks callbacks = getCallback();
|
||||
// Process the newly added applications and add them to the database first
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
|
||||
|
||||
ArrayList<Long> workspaceScreens = new ArrayList<Long>();
|
||||
TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);
|
||||
for (Integer i : orderedScreens.keySet()) {
|
||||
long screenId = orderedScreens.get(i);
|
||||
workspaceScreens.add(screenId);
|
||||
}
|
||||
|
||||
// Find appropriate space for the item.
|
||||
Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
|
||||
fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,
|
||||
addInfo.spanX,
|
||||
addInfo.spanY);
|
||||
final long screenId = coords.first;
|
||||
final int[] cordinates = coords.second;
|
||||
|
||||
// Update the workspace screens
|
||||
updateWorkspaceScreenOrder(context, workspaceScreens);
|
||||
runOnMainThread(new Runnable() {
|
||||
public void run() {
|
||||
Callbacks cb = getCallback();
|
||||
if (callbacks == cb && cb != null) {
|
||||
cb.bindAddScreens(addedWorkspaceScreensFinal);
|
||||
cb.bindAddPendingItem(addInfo,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP,
|
||||
screenId, cordinates, addInfo.spanX, addInfo.spanY);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
runOnWorkerThread(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provided items to the workspace.
|
||||
* @param preferredScreen the screen where we should try to add the app first
|
||||
* @param fallbackStartScreen the screen to start search for empty space if
|
||||
* preferredScreen is not available.
|
||||
*/
|
||||
public void addAndBindAddedWorkspaceApps(final Context context,
|
||||
final ArrayList<ItemInfo> workspaceApps,
|
||||
final ScreenPosProvider preferredScreen,
|
||||
final int fallbackStartScreen,
|
||||
final boolean allowDuplicate) {
|
||||
final Callbacks callbacks = getCallback();
|
||||
if (workspaceApps.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -427,53 +557,27 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
|
||||
synchronized(sBgLock) {
|
||||
Iterator<ItemInfo> iter = workspaceApps.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ItemInfo a = iter.next();
|
||||
final String name = a.title.toString();
|
||||
final Intent launchIntent = a.getIntent();
|
||||
|
||||
// Short-circuit this logic if the icon exists somewhere on the workspace
|
||||
if (shortcutExists(context, name, launchIntent, a.user)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add this icon to the db, creating a new page if necessary. If there
|
||||
// is only the empty page then we just add items to the first page.
|
||||
// Otherwise, we add them to the next pages.
|
||||
int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;
|
||||
Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,
|
||||
name, launchIntent, startSearchPageIndex, workspaceScreens);
|
||||
if (coords == null) {
|
||||
LauncherProvider lp = LauncherAppState.getLauncherProvider();
|
||||
|
||||
// If we can't find a valid position, then just add a new screen.
|
||||
// This takes time so we need to re-queue the add until the new
|
||||
// page is added. Create as many screens as necessary to satisfy
|
||||
// the startSearchPageIndex.
|
||||
int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -
|
||||
workspaceScreens.size());
|
||||
while (numPagesToAdd > 0) {
|
||||
long screenId = lp.generateNewScreenId();
|
||||
// Save the screen id for binding in the workspace
|
||||
workspaceScreens.add(screenId);
|
||||
addedWorkspaceScreensFinal.add(screenId);
|
||||
numPagesToAdd--;
|
||||
for (ItemInfo item : workspaceApps) {
|
||||
if (!allowDuplicate) {
|
||||
// Short-circuit this logic if the icon exists somewhere on the workspace
|
||||
if (shortcutExists(context, item.title.toString(),
|
||||
item.getIntent(), item.user)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the coordinate again
|
||||
coords = LauncherModel.findNextAvailableIconSpace(context,
|
||||
name, launchIntent, startSearchPageIndex, workspaceScreens);
|
||||
}
|
||||
if (coords == null) {
|
||||
throw new RuntimeException("Coordinates should not be null");
|
||||
}
|
||||
// Find appropriate space for the item.
|
||||
Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
|
||||
fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,
|
||||
1, 1);
|
||||
long screenId = coords.first;
|
||||
int[] cordinates = coords.second;
|
||||
|
||||
ShortcutInfo shortcutInfo;
|
||||
if (a instanceof ShortcutInfo) {
|
||||
shortcutInfo = (ShortcutInfo) a;
|
||||
} else if (a instanceof AppInfo) {
|
||||
shortcutInfo = ((AppInfo) a).makeShortcut();
|
||||
if (item instanceof ShortcutInfo) {
|
||||
shortcutInfo = (ShortcutInfo) item;
|
||||
} else if (item instanceof AppInfo) {
|
||||
shortcutInfo = ((AppInfo) item).makeShortcut();
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected info type");
|
||||
}
|
||||
@@ -481,7 +585,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
// Add the shortcut to the db
|
||||
addItemToDatabase(context, shortcutInfo,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP,
|
||||
coords.first, coords.second[0], coords.second[1], false);
|
||||
screenId, cordinates[0], cordinates[1], false);
|
||||
// Save the ShortcutInfo for binding in the workspace
|
||||
addedShortcutsFinal.add(shortcutInfo);
|
||||
}
|
||||
@@ -717,35 +821,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
public void flushWorkerThread() {
|
||||
mFlushingWorkerThread = true;
|
||||
Runnable waiter = new Runnable() {
|
||||
public void run() {
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
mFlushingWorkerThread = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
synchronized(waiter) {
|
||||
runOnWorkerThread(waiter);
|
||||
if (mLoaderTask != null) {
|
||||
synchronized(mLoaderTask) {
|
||||
mLoaderTask.notify();
|
||||
}
|
||||
}
|
||||
boolean success = false;
|
||||
while (!success) {
|
||||
try {
|
||||
waiter.wait();
|
||||
success = true;
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an item in the DB to a new <container, screen, cellX, cellY>
|
||||
*/
|
||||
@@ -889,57 +964,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ItemInfo array containing all the items in the LauncherModel.
|
||||
* The ItemInfo.id is not set through this function.
|
||||
*/
|
||||
static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {
|
||||
ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
|
||||
LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
|
||||
LauncherSettings.Favorites.SCREEN,
|
||||
LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
|
||||
LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY,
|
||||
LauncherSettings.Favorites.PROFILE_ID }, null, null, null);
|
||||
|
||||
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
|
||||
final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
|
||||
final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
|
||||
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
|
||||
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
|
||||
final int rankIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RANK);
|
||||
final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
|
||||
final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
|
||||
final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
|
||||
UserManagerCompat userManager = UserManagerCompat.getInstance(context);
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
ItemInfo item = new ItemInfo();
|
||||
item.cellX = c.getInt(cellXIndex);
|
||||
item.cellY = c.getInt(cellYIndex);
|
||||
item.rank = c.getInt(rankIndex);
|
||||
item.spanX = Math.max(1, c.getInt(spanXIndex));
|
||||
item.spanY = Math.max(1, c.getInt(spanYIndex));
|
||||
item.container = c.getInt(containerIndex);
|
||||
item.itemType = c.getInt(itemTypeIndex);
|
||||
item.screenId = c.getInt(screenIndex);
|
||||
long serialNumber = c.getInt(profileIdIndex);
|
||||
item.user = userManager.getUserForSerialNumber(serialNumber);
|
||||
// Skip if user has been deleted.
|
||||
if (item.user != null) {
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
items.clear();
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
|
||||
*/
|
||||
@@ -1543,7 +1567,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
});
|
||||
|
||||
while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {
|
||||
while (!mStopped && !mLoadAndBindStepFinished) {
|
||||
try {
|
||||
// Just in case mFlushingWorkerThread changes but we aren't woken up,
|
||||
// wait no longer than 1sec at a time
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
@@ -67,6 +66,7 @@ public class PagedViewWidget extends LinearLayout {
|
||||
|
||||
setWillNotDraw(false);
|
||||
setClipToPadding(false);
|
||||
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -54,12 +54,11 @@ class PreloadIconDrawable extends Drawable {
|
||||
mPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
|
||||
setBounds(icon.getBounds());
|
||||
applyTheme(theme);
|
||||
applyPreloaderTheme(theme);
|
||||
onLevelChange(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Theme t) {
|
||||
public void applyPreloaderTheme(Theme t) {
|
||||
TypedArray ta = t.obtainStyledAttributes(R.styleable.PreloadIconDrawable);
|
||||
mBgDrawable = ta.getDrawable(R.styleable.PreloadIconDrawable_background);
|
||||
mBgDrawable.setFilterBitmap(true);
|
||||
|
||||
@@ -31,10 +31,7 @@ import android.appwidget.AppWidgetHostView;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -77,8 +74,6 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
@@ -92,9 +87,6 @@ public class Workspace extends SmoothPagedView
|
||||
Insettable {
|
||||
private static final String TAG = "Launcher.Workspace";
|
||||
|
||||
// Y rotation to apply to the workspace screens
|
||||
private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
|
||||
|
||||
private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
|
||||
private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
|
||||
private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
|
||||
@@ -228,7 +220,6 @@ public class Workspace extends SmoothPagedView
|
||||
private Runnable mDelayedResizeRunnable;
|
||||
private Runnable mDelayedSnapToPageRunnable;
|
||||
private Point mDisplaySize = new Point();
|
||||
private int mCameraDistance;
|
||||
|
||||
// Variables relating to the creation of user folders by hovering shortcuts over shortcuts
|
||||
private static final int FOLDER_CREATION_TIMEOUT = 0;
|
||||
@@ -346,7 +337,6 @@ public class Workspace extends SmoothPagedView
|
||||
mSpringLoadedShrinkFactor =
|
||||
res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
|
||||
mOverviewModeShrinkFactor = grid.getOverviewModeScale();
|
||||
mCameraDistance = res.getInteger(R.integer.config_cameraDistance);
|
||||
mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
|
||||
a.recycle();
|
||||
|
||||
@@ -450,7 +440,6 @@ public class Workspace extends SmoothPagedView
|
||||
*/
|
||||
protected void initWorkspace() {
|
||||
mCurrentPage = mDefaultPage;
|
||||
Launcher.setScreen(mCurrentPage);
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
mIconCache = app.getIconCache();
|
||||
@@ -1323,7 +1312,6 @@ public class Workspace extends SmoothPagedView
|
||||
@Override
|
||||
protected void notifyPageSwitchListener() {
|
||||
super.notifyPageSwitchListener();
|
||||
Launcher.setScreen(getNextPage());
|
||||
|
||||
if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {
|
||||
mCustomContentShowing = true;
|
||||
@@ -3952,23 +3940,8 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
// When dragging and dropping from customization tray, we deal with creating
|
||||
// widgets/shortcuts/folders in a slightly different way
|
||||
switch (pendingInfo.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
|
||||
int span[] = new int[2];
|
||||
span[0] = item.spanX;
|
||||
span[1] = item.spanY;
|
||||
mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
|
||||
container, screenId, mTargetCell, span, null);
|
||||
break;
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
mLauncher.processShortcutFromDrop(pendingInfo.componentName,
|
||||
container, screenId, mTargetCell, null);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown item type: " +
|
||||
pendingInfo.itemType);
|
||||
}
|
||||
mLauncher.addPendingItem(pendingInfo, container, screenId, mTargetCell,
|
||||
item.spanX, item.spanY);
|
||||
}
|
||||
};
|
||||
boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
|
||||
@@ -3998,7 +3971,7 @@ public class Workspace extends SmoothPagedView
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
if (info.container == NO_ID && info instanceof AppInfo) {
|
||||
// Came from all apps -- make a copy
|
||||
info = new ShortcutInfo((AppInfo) info);
|
||||
info = ((AppInfo) info).makeShortcut();
|
||||
}
|
||||
view = mLauncher.createShortcut(R.layout.application, cellLayout,
|
||||
(ShortcutInfo) info);
|
||||
@@ -4250,15 +4223,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {
|
||||
if (target != this && mDragInfo != null) {
|
||||
CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);
|
||||
if (parentCell != null) {
|
||||
parentCell.removeView(mDragInfo.cell);
|
||||
} else if (LauncherAppState.isDogfoodBuild()) {
|
||||
throw new NullPointerException("mDragInfo.cell has null parent");
|
||||
}
|
||||
if (mDragInfo.cell instanceof DropTarget) {
|
||||
mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
|
||||
}
|
||||
removeWorkspaceItem(mDragInfo.cell);
|
||||
}
|
||||
} else if (mDragInfo != null) {
|
||||
CellLayout cellLayout;
|
||||
@@ -4283,6 +4248,18 @@ public class Workspace extends SmoothPagedView
|
||||
mDragInfo = null;
|
||||
}
|
||||
|
||||
public void removeWorkspaceItem(View v) {
|
||||
CellLayout parentCell = getParentCellLayoutForView(v);
|
||||
if (parentCell != null) {
|
||||
parentCell.removeView(v);
|
||||
} else if (LauncherAppState.isDogfoodBuild()) {
|
||||
throw new NullPointerException("mDragInfo.cell has null parent");
|
||||
}
|
||||
if (v instanceof DropTarget) {
|
||||
mDragController.removeDropTarget((DropTarget) v);
|
||||
}
|
||||
}
|
||||
|
||||
public void deferCompleteDropAfterUninstallActivity() {
|
||||
mDeferDropAfterUninstall = true;
|
||||
}
|
||||
@@ -4477,12 +4454,6 @@ public class Workspace extends SmoothPagedView
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
super.onRestoreInstanceState(state);
|
||||
Launcher.setScreen(mCurrentPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
|
||||
// We don't dispatch restoreInstanceState to our children using this code path.
|
||||
|
||||
Reference in New Issue
Block a user