diff options
Diffstat (limited to 'src/com/android/launcher3')
21 files changed, 1000 insertions, 372 deletions
diff --git a/src/com/android/launcher3/Alarm.java b/src/com/android/launcher3/Alarm.java index 91f9bd091..e9f1fd963 100644 --- a/src/com/android/launcher3/Alarm.java +++ b/src/com/android/launcher3/Alarm.java @@ -78,7 +78,3 @@ public class Alarm implements Runnable{ return mAlarmPending; } } - -interface OnAlarmListener { - public void onAlarm(Alarm alarm); -} diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index 2865bc5d5..37cdb9e13 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -199,8 +199,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f); private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4); - public static boolean DISABLE_ALL_APPS = false; - // Previews & outlines ArrayList<AppsCustomizeAsyncTask> mRunningTasks; private static final int sPageSleepDelay = 200; @@ -427,7 +425,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (!isDataReady()) { - if ((DISABLE_ALL_APPS || !mApps.isEmpty()) && !mWidgets.isEmpty()) { + if ((LauncherAppState.isDisableAllApps() || !mApps.isEmpty()) && !mWidgets.isEmpty()) { setDataIsReady(); setMeasuredDimension(width, height); onDataReady(width, height); @@ -1558,7 +1556,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } public void setApps(ArrayList<AppInfo> list) { - if (!DISABLE_ALL_APPS) { + if (!LauncherAppState.isDisableAllApps()) { mApps = list; Collections.sort(mApps, LauncherModel.getAppNameComparator()); updatePageCountsAndInvalidateData(); @@ -1576,7 +1574,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } public void addApps(ArrayList<AppInfo> list) { - if (!DISABLE_ALL_APPS) { + if (!LauncherAppState.isDisableAllApps()) { addAppsWithoutInvalidate(list); updatePageCountsAndInvalidateData(); } @@ -1604,7 +1602,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } public void removeApps(ArrayList<AppInfo> appInfos) { - if (!DISABLE_ALL_APPS) { + if (!LauncherAppState.isDisableAllApps()) { removeAppsWithoutInvalidate(appInfos); updatePageCountsAndInvalidateData(); } @@ -1613,7 +1611,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // We remove and re-add the updated applications list because it's properties may have // changed (ie. the title), and this will ensure that the items will be in their proper // place in the list. - if (!DISABLE_ALL_APPS) { + if (!LauncherAppState.isDisableAllApps()) { removeAppsWithoutInvalidate(list); addAppsWithoutInvalidate(list); updatePageCountsAndInvalidateData(); @@ -1727,4 +1725,4 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen return String.format(getContext().getString(stringId), page + 1, count); } -} +}
\ No newline at end of file diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java index 697bd7ecf..bb7f045ce 100644 --- a/src/com/android/launcher3/AppsCustomizeTabHost.java +++ b/src/com/android/launcher3/AppsCustomizeTabHost.java @@ -407,7 +407,7 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona } // Dismiss the workspace cling - l.dismissWorkspaceCling(null); + l.getLauncherClings().dismissWorkspaceCling(null); } @Override diff --git a/src/com/android/launcher3/BuildInfo.java b/src/com/android/launcher3/BuildInfo.java new file mode 100644 index 000000000..b49ee0d9b --- /dev/null +++ b/src/com/android/launcher3/BuildInfo.java @@ -0,0 +1,32 @@ +package com.android.launcher3; + +import android.text.TextUtils; +import android.util.Log; + +public class BuildInfo { + private static final boolean DBG = false; + private static final String TAG = "BuildInfo"; + + public boolean isDogfoodBuild() { + return false; + } + + public static BuildInfo loadByName(String className) { + if (TextUtils.isEmpty(className)) return new BuildInfo(); + + if (DBG) Log.d(TAG, "Loading BuildInfo: " + className); + try { + Class<?> cls = Class.forName(className); + return (BuildInfo) cls.newInstance(); + } catch (ClassNotFoundException e) { + Log.e(TAG, "Bad BuildInfo class", e); + } catch (InstantiationException e) { + Log.e(TAG, "Bad BuildInfo class", e); + } catch (IllegalAccessException e) { + Log.e(TAG, "Bad BuildInfo class", e); + } catch (ClassCastException e) { + Log.e(TAG, "Bad BuildInfo class", e); + } + return new BuildInfo(); + } +} diff --git a/src/com/android/launcher3/Cling.java b/src/com/android/launcher3/Cling.java index 3af427139..185b49b08 100644 --- a/src/com/android/launcher3/Cling.java +++ b/src/com/android/launcher3/Cling.java @@ -37,10 +37,6 @@ import android.widget.TextView; public class Cling extends FrameLayout implements Insettable, View.OnClickListener, View.OnLongClickListener, View.OnTouchListener { - static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed"; - static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed"; - static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed"; - private static String FIRST_RUN_PORTRAIT = "first_run_portrait"; private static String FIRST_RUN_LANDSCAPE = "first_run_landscape"; @@ -49,6 +45,12 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen private static String WORKSPACE_LARGE = "workspace_large"; private static String WORKSPACE_CUSTOM = "workspace_custom"; + private static String MIGRATION_PORTRAIT = "migration_portrait"; + private static String MIGRATION_LANDSCAPE = "migration_landscape"; + + private static String MIGRATION_WORKSPACE_PORTRAIT = "migration_workspace_portrait"; + private static String MIGRATION_WORKSPACE_LANDSCAPE = "migration_workspace_landscape"; + private static String FOLDER_PORTRAIT = "folder_portrait"; private static String FOLDER_LANDSCAPE = "folder_landscape"; private static String FOLDER_LARGE = "folder_large"; @@ -57,6 +59,8 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen private static float WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 50; private static float WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 60; private static float WORKSPACE_CIRCLE_Y_OFFSET_DPS = 30; + private static float MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 42; + private static float MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 46; private Launcher mLauncher; private boolean mIsInitialized; @@ -70,6 +74,7 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen private Rect mFocusedHotseatAppBounds; private Paint mErasePaint; + private Paint mBorderPaint; private Paint mBubblePaint; private Paint mDotPaint; @@ -112,6 +117,10 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen mErasePaint.setAlpha(0); mErasePaint.setAntiAlias(true); + mBorderPaint = new Paint(); + mBorderPaint.setColor(0xFFFFFFFF); + mBorderPaint.setAntiAlias(true); + int circleColor = getResources().getColor( R.color.first_run_cling_circle_background_color); mBubblePaint = new Paint(); @@ -166,13 +175,30 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen } } + void updateMigrationWorkspaceBubblePosition() { + DisplayMetrics metrics = new DisplayMetrics(); + mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics); + + // Get the page indicator bounds + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + Rect pageIndicatorBounds = grid.getWorkspacePageIndicatorBounds(mInsets); + + View bubble = findViewById(R.id.migration_workspace_cling_bubble); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) bubble.getLayoutParams(); + lp.bottomMargin = grid.heightPx - pageIndicatorBounds.top; + bubble.requestLayout(); + } + void show(boolean animate, int duration) { setVisibility(View.VISIBLE); setLayerType(View.LAYER_TYPE_HARDWARE, null); if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || mDrawIdentifier.equals(WORKSPACE_LARGE) || - mDrawIdentifier.equals(WORKSPACE_CUSTOM)) { + mDrawIdentifier.equals(WORKSPACE_CUSTOM) || + mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || + mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { View content = getContent(); content.setAlpha(0f); content.animate() @@ -218,7 +244,9 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen void hide(final int duration, final Runnable postCb) { if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) || - mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE)) { + mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE) || + mDrawIdentifier.equals(MIGRATION_PORTRAIT) || + mDrawIdentifier.equals(MIGRATION_LANDSCAPE)) { View content = getContent(); content.animate() .alpha(0f) @@ -340,7 +368,7 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen intent.setComponent(mFocusedHotseatAppComponent); intent.addCategory(Intent.CATEGORY_LAUNCHER); mLauncher.startActivity(intent, null); - mLauncher.dismissWorkspaceCling(this); + mLauncher.getLauncherClings().dismissWorkspaceCling(this); } } } @@ -350,7 +378,11 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || mDrawIdentifier.equals(WORKSPACE_LARGE)) { - mLauncher.dismissWorkspaceCling(null); + mLauncher.getLauncherClings().dismissWorkspaceCling(null); + return true; + } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || + mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { + mLauncher.getLauncherClings().dismissMigrationWorkspaceCling(null); return true; } return false; @@ -361,6 +393,11 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen if (mIsInitialized) { canvas.save(); + // Get the page indicator bounds + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + Rect pageIndicatorBounds = grid.getWorkspacePageIndicatorBounds(mInsets); + // Get the background override if there is one if (mBackground == null) { if (mDrawIdentifier.equals(WORKSPACE_CUSTOM)) { @@ -378,7 +415,9 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen mBackground.draw(canvas); } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || - mDrawIdentifier.equals(WORKSPACE_LARGE)) { + mDrawIdentifier.equals(WORKSPACE_LARGE) || + mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || + mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { // Initialize the draw buffer (to allow punching through) eraseBg = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); @@ -412,11 +451,13 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || mDrawIdentifier.equals(WORKSPACE_LARGE)) { int offset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics); - mErasePaint.setAlpha((int) (128)); + // Draw the outer circle + mErasePaint.setAlpha(128); eraseCanvas.drawCircle(metrics.widthPixels / 2, metrics.heightPixels / 2 - offset, DynamicGrid.pxFromDp(WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics), mErasePaint); + // Draw the inner circle mErasePaint.setAlpha(0); eraseCanvas.drawCircle(metrics.widthPixels / 2, metrics.heightPixels / 2 - offset, @@ -434,8 +475,24 @@ public class Cling extends FrameLayout implements Insettable, View.OnClickListen mFocusedHotseatApp.setAlpha((int) (255 * alpha)); mFocusedHotseatApp.draw(canvas); } + } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || + mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { + int offset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics); + // Draw the outer circle + eraseCanvas.drawCircle(pageIndicatorBounds.centerX(), + pageIndicatorBounds.centerY(), + DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics), + mBorderPaint); + // Draw the inner circle + mErasePaint.setAlpha(0); + eraseCanvas.drawCircle(pageIndicatorBounds.centerX(), + pageIndicatorBounds.centerY(), + DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS, metrics), + mErasePaint); + canvas.drawBitmap(eraseBg, 0, 0, null); + eraseCanvas.setBitmap(null); + eraseBg = null; } - canvas.restore(); } diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index c76425a5e..75d906bc2 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -146,12 +146,12 @@ public class DeleteDropTarget extends ButtonDropTarget { return true; } - if (!AppsCustomizePagedView.DISABLE_ALL_APPS && + if (!LauncherAppState.isDisableAllApps() && item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { return true; } - if (!AppsCustomizePagedView.DISABLE_ALL_APPS && + if (!LauncherAppState.isDisableAllApps() && item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && item instanceof AppInfo) { AppInfo appInfo = (AppInfo) info; @@ -160,7 +160,7 @@ public class DeleteDropTarget extends ButtonDropTarget { if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && item instanceof ShortcutInfo) { - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { ShortcutInfo shortcutInfo = (ShortcutInfo) info; return (shortcutInfo.flags & AppInfo.DOWNLOADED_FLAG) != 0; } else { @@ -174,7 +174,7 @@ public class DeleteDropTarget extends ButtonDropTarget { @Override public void onDragStart(DragSource source, Object info, int dragAction) { boolean isVisible = true; - boolean useUninstallLabel = !AppsCustomizePagedView.DISABLE_ALL_APPS && + boolean useUninstallLabel = !LauncherAppState.isDisableAllApps() && isAllAppsApplication(source, info); boolean useDeleteLabel = !useUninstallLabel && source.supportsDeleteDropTarget(); @@ -264,7 +264,7 @@ public class DeleteDropTarget extends ButtonDropTarget { } private boolean isUninstallFromWorkspace(DragObject d) { - if (AppsCustomizePagedView.DISABLE_ALL_APPS && isWorkspaceOrFolderApplication(d)) { + if (LauncherAppState.isDisableAllApps() && isWorkspaceOrFolderApplication(d)) { ShortcutInfo shortcut = (ShortcutInfo) d.dragInfo; // Only allow manifest shortcuts to initiate an un-install. return !InstallShortcutReceiver.isValidShortcutLaunchIntent(shortcut.intent); diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 67b0933c9..a64d5e403 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -126,7 +126,7 @@ public class DeviceProfile { DeviceProfile(String n, float w, float h, float r, float c, float is, float its, float hs, float his) { // Ensure that we have an odd number of hotseat items (since we need to place all apps) - if (!AppsCustomizePagedView.DISABLE_ALL_APPS && hs % 2 == 0) { + if (!LauncherAppState.isDisableAllApps() && hs % 2 == 0) { throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces"); } @@ -475,6 +475,14 @@ public class DeviceProfile { return bounds; } + /** Returns the bounds of the workspace page indicators. */ + Rect getWorkspacePageIndicatorBounds(Rect insets) { + Rect workspacePadding = getWorkspacePadding(); + int pageIndicatorTop = heightPx - insets.bottom - workspacePadding.bottom; + return new Rect(workspacePadding.left, pageIndicatorTop, + widthPx - workspacePadding.right, pageIndicatorTop + pageIndicatorHeightPx); + } + /** Returns the workspace padding in the specified orientation */ Rect getWorkspacePadding() { return getWorkspacePadding(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT); diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index 8726f30c1..ab0469d53 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -168,7 +168,8 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang } Folder currentFolder = mLauncher.getWorkspace().getOpenFolder(); - if (currentFolder != null && !mLauncher.isFolderClingVisible() && intercept) { + if (currentFolder != null && !mLauncher.getLauncherClings().isFolderClingVisible() && + intercept) { if (currentFolder.isEditingName()) { if (!isEventOverFolderTextRegion(currentFolder, ev)) { currentFolder.dismissEditingName(); diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java index 22928ccf3..3aced1fae 100644 --- a/src/com/android/launcher3/DynamicGrid.java +++ b/src/com/android/launcher3/DynamicGrid.java @@ -56,7 +56,7 @@ public class DynamicGrid { DisplayMetrics dm = resources.getDisplayMetrics(); ArrayList<DeviceProfile> deviceProfiles = new ArrayList<DeviceProfile>(); - boolean hasAA = !AppsCustomizePagedView.DISABLE_ALL_APPS; + boolean hasAA = !LauncherAppState.isDisableAllApps(); DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm); // Our phone profiles include the bar sizes in each orientation deviceProfiles.add(new DeviceProfile("Super Short Stubby", diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index ca82bd1a7..a9134e105 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -146,7 +146,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList Resources res = getResources(); mMaxCountX = (int) grid.numColumns; // Allow scrolling folders when DISABLE_ALL_APPS is true. - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { mMaxCountY = mMaxNumItems = Integer.MAX_VALUE; } else { mMaxCountY = (int) grid.numRows; @@ -238,7 +238,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList return false; } - mLauncher.dismissFolderCling(null); + mLauncher.getLauncherClings().dismissFolderCling(null); mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); @@ -466,7 +466,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void onAnimationEnd(Animator animation) { mState = STATE_OPEN; setLayerType(LAYER_TYPE_NONE, null); - Cling cling = mLauncher.showFirstRunFoldersCling(); + Cling cling = mLauncher.getLauncherClings().showFoldersCling(); if (cling != null) { cling.bringScrimToFront(); bringToFront(); @@ -773,7 +773,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } completeDragExit(); } - } else { + } + + // This is kind of hacky, but in general, dropping on the workspace handles removing + // the extra screen, but dropping elsewhere (back to self, or onto delete) doesn't. + if (target != mLauncher.getWorkspace()) { mLauncher.getWorkspace().removeExtraEmptyScreen(true, null); } @@ -1014,7 +1018,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(), MeasureSpec.EXACTLY); - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { // Don't cap the height of the content to allow scrolling. mContent.setFixedSize(getContentAreaWidth(), mContent.getDesiredHeight()); } else { @@ -1103,7 +1107,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList if (getItemCount() <= 1) { // Remove the folder LauncherModel.deleteItemFromDatabase(mLauncher, mInfo); - cellLayout.removeView(mFolderIcon); + if (cellLayout != null) { + // b/12446428 -- sometimes the cell layout has already gone away? + cellLayout.removeView(mFolderIcon); + } if (mFolderIcon instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) mFolderIcon); } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 094e188c7..59d60e381 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -95,7 +95,7 @@ public class Hotseat extends FrameLayout { return hasVerticalHotseat() ? (mContent.getCountY() - (rank + 1)) : 0; } public boolean isAllAppsButtonRank(int rank) { - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { return false; } else { return rank == mAllAppsButtonRank; @@ -142,7 +142,7 @@ public class Hotseat extends FrameLayout { void resetLayout() { mContent.removeAllViewsInLayout(); - if (!AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (!LauncherAppState.isDisableAllApps()) { // Add the Apps button Context context = getContext(); @@ -189,7 +189,7 @@ public class Hotseat extends FrameLayout { void addAllAppsFolder(IconCache iconCache, ArrayList<AppInfo> allApps, ArrayList<ComponentName> onWorkspace, Launcher launcher, Workspace workspace) { - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { FolderInfo fi = new FolderInfo(); fi.cellX = getCellXFromOrder(mAllAppsButtonRank); @@ -219,7 +219,7 @@ public class Hotseat extends FrameLayout { } void addAppsToAllAppsFolder(ArrayList<AppInfo> apps) { - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { View v = mContent.getChildAt(getCellXFromOrder(mAllAppsButtonRank), getCellYFromOrder(mAllAppsButtonRank)); FolderIcon fi = null; diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 1ff94720b..7ab4e0477 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -272,7 +272,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { final Intent intent = pendingInfo.launchIntent; final String name = pendingInfo.name; - if (AppsCustomizePagedView.DISABLE_ALL_APPS && !isValidShortcutLaunchIntent(intent)) { + if (LauncherAppState.isDisableAllApps() && !isValidShortcutLaunchIntent(intent)) { if (DBG) Log.d(TAG, "Ignoring shortcut with launchIntent:" + intent); continue; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c05769cfa..765fca499 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -17,8 +17,6 @@ package com.android.launcher3; -import android.accounts.Account; -import android.accounts.AccountManager; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -87,7 +85,6 @@ import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; @@ -115,6 +112,7 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; + /** * Default launcher application. */ @@ -130,6 +128,8 @@ public class Launcher extends Activity static final boolean DEBUG_RESUME_TIME = false; static final boolean DEBUG_DUMP_LOG = false; + static final boolean ENABLE_DEBUG_INTENTS = false; // allow DebugIntents to run + private static final int REQUEST_CREATE_SHORTCUT = 1; private static final int REQUEST_CREATE_APPWIDGET = 5; private static final int REQUEST_PICK_APPLICATION = 6; @@ -155,6 +155,7 @@ public class Launcher extends Activity // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS] static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate"; static final String DUMP_STATE_PROPERTY = "launcher_dump_state"; + static final String DISABLE_ALL_APPS_PROPERTY = "launcher_noallapps"; // The Intent extra that defines whether to ignore the launch animation static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = @@ -187,6 +188,9 @@ public class Launcher extends Activity // Type: int[] private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids"; + + static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed"; + private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon"; private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME = "com.android.launcher.toolbar_search_icon"; @@ -196,6 +200,8 @@ public class Launcher extends Activity public static final String SHOW_WEIGHT_WATCHER = "debug.show_mem"; public static final boolean SHOW_WEIGHT_WATCHER_DEFAULT = false; + public static final String USER_HAS_MIGRATED = "launcher.user_migrated_from_old_data"; + /** The different states that Launcher can be in. */ private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED }; private State mState = State.WORKSPACE; @@ -204,8 +210,6 @@ public class Launcher extends Activity static final int APPWIDGET_HOST_ID = 1024; public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300; private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500; - private static final int SHOW_CLING_DURATION = 250; - private static final int DISMISS_CLING_DURATION = 200; private static final Object sLock = new Object(); private static int sScreen = DEFAULT_SCREEN; @@ -226,9 +230,11 @@ public class Launcher extends Activity private Workspace mWorkspace; private View mLauncherView; + private View mPageIndicators; private DragLayer mDragLayer; private DragController mDragController; private View mWeightWatcher; + private LauncherClings mLauncherClings; private AppWidgetManager mAppWidgetManager; private LauncherAppWidgetHost mAppWidgetHost; @@ -281,8 +287,6 @@ public class Launcher extends Activity private boolean mVisible = false; private boolean mHasFocus = false; private boolean mAttached = false; - private static final boolean DISABLE_CLINGS = false; - private static final boolean DISABLE_CUSTOM_CLINGS = true; private static LocaleConfiguration sLocaleConfiguration = null; @@ -338,9 +342,6 @@ public class Launcher extends Activity private BubbleTextView mWaitingForResume; - private HideFromAccessibilityHelper mHideFromAccessibilityHelper - = new HideFromAccessibilityHelper(); - private Runnable mBuildLayersRunnable = new Runnable() { public void run() { if (mWorkspace != null) { @@ -365,7 +366,7 @@ public class Launcher extends Activity private Stats mStats; - private static boolean isPropertyEnabled(String propertyName) { + static boolean isPropertyEnabled(String propertyName) { return Log.isLoggable(propertyName, Log.VERBOSE); } @@ -415,6 +416,7 @@ public class Launcher extends Activity mIconCache = app.getIconCache(); mIconCache.flushInvalidIcons(grid); mDragController = new DragController(this); + mLauncherClings = new LauncherClings(this); mInflater = getLayoutInflater(); mStats = new Stats(this); @@ -476,7 +478,12 @@ public class Launcher extends Activity // On large interfaces, we want the screen to auto-rotate based on the current orientation unlockScreenOrientation(true); - showFirstRunCling(); + showFirstRunActivity(); + if (mModel.canMigrateFromOldLauncherDb()) { + mLauncherClings.showMigrationCling(); + } else { + mLauncherClings.showFirstRunCling(); + } } protected void onUserLeaveHint() { @@ -498,6 +505,21 @@ public class Launcher extends Activity } /** + * To be overridden by subclasses to indicate that there is an activity to launch + * before showing the standard launcher experience. + */ + protected boolean hasFirstRunActivity() { + return false; + } + + /** + * To be overridden by subclasses to launch any first run activity + */ + protected Intent getFirstRunActivity() { + return null; + } + + /** * Invoked by subclasses to signal a change to the {@link #addCustomContentToLeft} value to * ensure the custom content page is added or removed if necessary. */ @@ -654,10 +676,6 @@ public class Launcher extends Activity return mInflater; } - public DragLayer getDragLayer() { - return mDragLayer; - } - boolean isDraggingEnabled() { // We prevent dragging when we are loading the workspace as it is possible to pick up a view // that is subsequently removed from the workspace in startBinding(). @@ -1208,6 +1226,7 @@ public class Launcher extends Activity mLauncherView = findViewById(R.id.launcher); mDragLayer = (DragLayer) findViewById(R.id.drag_layer); mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace); + mPageIndicators = mDragLayer.findViewById(R.id.page_indicator); mLauncherView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); @@ -1551,6 +1570,15 @@ public class Launcher extends Activity } else if (Intent.ACTION_USER_PRESENT.equals(action)) { mUserPresent = true; updateRunning(); + } else if (ENABLE_DEBUG_INTENTS && DebugIntents.DELETE_DATABASE.equals(action)) { + mModel.resetLoadedState(false, true); + mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE); + } else if (ENABLE_DEBUG_INTENTS && DebugIntents.MIGRATE_DATABASE.equals(action)) { + mModel.resetLoadedState(false, true); + mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE + | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS); } } }; @@ -1563,6 +1591,10 @@ public class Launcher extends Activity final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); + if (ENABLE_DEBUG_INTENTS) { + filter.addAction(DebugIntents.DELETE_DATABASE); + filter.addAction(DebugIntents.MIGRATE_DATABASE); + } registerReceiver(mReceiver, filter); FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView()); mAttached = true; @@ -1702,6 +1734,26 @@ public class Launcher extends Activity Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show(); } + public DragLayer getDragLayer() { + return mDragLayer; + } + + public Workspace getWorkspace() { + return mWorkspace; + } + + public Hotseat getHotseat() { + return mHotseat; + } + + public View getOverviewPanel() { + return mOverviewPanel; + } + + public SearchDropTargetBar getSearchBar() { + return mSearchDropTargetBar; + } + public LauncherAppWidgetHost getAppWidgetHost() { return mAppWidgetHost; } @@ -1710,6 +1762,14 @@ public class Launcher extends Activity return mModel; } + public LauncherClings getLauncherClings() { + return mLauncherClings; + } + + protected SharedPreferences getSharedPrefs() { + return mSharedPrefs; + } + public void closeSystemDialogs() { getWindow().closeAllPanels(); @@ -2671,7 +2731,7 @@ public class Launcher extends Activity closeFolder(folder); // Dismiss the folder cling - dismissFolderCling(null); + mLauncherClings.dismissFolderCling(null); } } @@ -2747,15 +2807,6 @@ public class Launcher extends Activity return mHotseat != null && layout != null && (layout instanceof CellLayout) && (layout == mHotseat.getLayout()); } - Hotseat getHotseat() { - return mHotseat; - } - View getOverviewPanel() { - return mOverviewPanel; - } - SearchDropTargetBar getSearchBar() { - return mSearchDropTargetBar; - } /** * Returns the CellLayout of the specified container at the specified screen. @@ -2772,10 +2823,6 @@ public class Launcher extends Activity } } - Workspace getWorkspace() { - return mWorkspace; - } - public boolean isAllAppsVisible() { return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE); } @@ -2906,7 +2953,7 @@ public class Launcher extends Activity // Shrink workspaces away if going to AppsCustomize from workspace Animator workspaceAnim = mWorkspace.getChangeStateAnimation(Workspace.State.SMALL, animated); - if (!AppsCustomizePagedView.DISABLE_ALL_APPS + if (!LauncherAppState.isDisableAllApps() || contentType == AppsCustomizePagedView.ContentType.Widgets) { // Set the content type for the all apps/widgets space mAppsCustomizeTabHost.setContentTypeImmediate(contentType); @@ -3777,7 +3824,7 @@ public class Launcher extends Activity // Remove the extra empty screen mWorkspace.removeExtraEmptyScreen(false, null); - if (!AppsCustomizePagedView.DISABLE_ALL_APPS && + if (!LauncherAppState.isDisableAllApps() && addedApps != null && mAppsCustomizeContent != null) { mAppsCustomizeContent.addApps(addedApps); } @@ -4044,7 +4091,7 @@ public class Launcher extends Activity * Implementation of the method from LauncherModel.Callbacks. */ public void bindAllApplications(final ArrayList<AppInfo> apps) { - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { if (mIntentsOnWorkspaceFromUpgradePath != null) { if (LauncherModel.UPGRADE_USE_MORE_APPS_FOLDER) { getHotseat().addAllAppsFolder(mIconCache, apps, @@ -4084,7 +4131,7 @@ public class Launcher extends Activity mWorkspace.updateShortcuts(apps); } - if (!AppsCustomizePagedView.DISABLE_ALL_APPS && + if (!LauncherAppState.isDisableAllApps() && mAppsCustomizeContent != null) { mAppsCustomizeContent.updateApps(apps); } @@ -4121,7 +4168,7 @@ public class Launcher extends Activity mDragController.onAppsRemoved(packageNames, appInfos); // Update AllApps - if (!AppsCustomizePagedView.DISABLE_ALL_APPS && + if (!LauncherAppState.isDisableAllApps() && mAppsCustomizeContent != null) { mAppsCustomizeContent.removeApps(appInfos); } @@ -4206,228 +4253,13 @@ public class Launcher extends Activity } } - /* Cling related */ - private boolean isClingsEnabled() { - if (DISABLE_CLINGS) { - return false; - } - - // For now, limit only to phones - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - if (grid.isTablet()) { - return false; - } - if (grid.isLandscape) { - return false; - } - - // disable clings when running in a test harness - if(ActivityManager.isRunningInTestHarness()) return false; - - // Disable clings for accessibility when explore by touch is enabled - final AccessibilityManager a11yManager = (AccessibilityManager) getSystemService( - ACCESSIBILITY_SERVICE); - if (a11yManager.isTouchExplorationEnabled()) { - return false; - } - - // Restricted secondary users (child mode) will potentially have very few apps - // seeded when they start up for the first time. Clings won't work well with that -// boolean supportsLimitedUsers = -// android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; -// Account[] accounts = AccountManager.get(this).getAccounts(); -// if (supportsLimitedUsers && accounts.length == 0) { -// UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); -// Bundle restrictions = um.getUserRestrictions(); -// if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { -// return false; -// } -// } - return true; - } - - private Cling initCling(int clingId, int scrimId, boolean animate, - boolean dimNavBarVisibilty) { - Cling cling = (Cling) findViewById(clingId); - View scrim = null; - if (scrimId > 0) { - scrim = findViewById(R.id.cling_scrim); - } - if (cling != null) { - cling.init(this, scrim); - cling.show(animate, SHOW_CLING_DURATION); - - if (dimNavBarVisibilty) { - cling.setSystemUiVisibility(cling.getSystemUiVisibility() | - View.SYSTEM_UI_FLAG_LOW_PROFILE); - } - } - return cling; - } - - private void dismissCling(final Cling cling, final Runnable postAnimationCb, - final String flag, int duration, boolean restoreNavBarVisibilty) { - // To catch cases where siblings of top-level views are made invisible, just check whether - // the cling is directly set to GONE before dismissing it. - if (cling != null && cling.getVisibility() != View.GONE) { - final Runnable cleanUpClingCb = new Runnable() { - public void run() { - cling.cleanup(); - // We should update the shared preferences on a background thread - new AsyncTask<Void, Void, Void>() { - public Void doInBackground(Void ... args) { - SharedPreferences.Editor editor = mSharedPrefs.edit(); - editor.putBoolean(flag, true); - editor.commit(); - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); - if (postAnimationCb != null) { - postAnimationCb.run(); - } - } - }; - if (duration <= 0) { - cleanUpClingCb.run(); - } else { - cling.hide(duration, cleanUpClingCb); - } - mHideFromAccessibilityHelper.restoreImportantForAccessibility(mDragLayer); - - if (restoreNavBarVisibilty) { - cling.setSystemUiVisibility(cling.getSystemUiVisibility() & - ~View.SYSTEM_UI_FLAG_LOW_PROFILE); - } - } - } - - private void removeCling(int id) { - final View cling = findViewById(id); - if (cling != null) { - final ViewGroup parent = (ViewGroup) cling.getParent(); - parent.post(new Runnable() { - @Override - public void run() { - parent.removeView(cling); - } - }); - mHideFromAccessibilityHelper.restoreImportantForAccessibility(mDragLayer); - } - } - - private boolean skipCustomClingIfNoAccounts() { - Cling cling = (Cling) findViewById(R.id.workspace_cling); - boolean customCling = cling.getDrawIdentifier().equals("workspace_custom"); - if (customCling) { - AccountManager am = AccountManager.get(this); - if (am == null) return false; - Account[] accounts = am.getAccountsByType("com.google"); - return accounts.length == 0; - } - return false; - } - - public void updateCustomContentHintVisibility() { - Cling cling = (Cling) findViewById(R.id.first_run_cling); - String ccHintStr = getFirstRunCustomContentHint(); - - if (mWorkspace.hasCustomContent()) { - // Show the custom content hint if ccHintStr is not empty - if (cling != null) { - setCustomContentHintVisibility(cling, ccHintStr, true, true); - } - } else { - // Hide the custom content hint - if (cling != null) { - setCustomContentHintVisibility(cling, ccHintStr, false, true); - } - } - } - - private void setCustomContentHintVisibility(Cling cling, String ccHintStr, boolean visible, - boolean animate) { - final TextView ccHint = (TextView) cling.findViewById(R.id.custom_content_hint); - if (ccHint != null) { - if (visible && !ccHintStr.isEmpty()) { - ccHint.setText(ccHintStr); - ccHint.setVisibility(View.VISIBLE); - if (animate) { - ccHint.setAlpha(0f); - ccHint.animate().alpha(1f) - .setDuration(SHOW_CLING_DURATION) - .start(); - } else { - ccHint.setAlpha(1f); - } - } else { - if (animate) { - ccHint.animate().alpha(0f) - .setDuration(SHOW_CLING_DURATION) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - ccHint.setVisibility(View.GONE); - } - }) - .start(); - } else { - ccHint.setAlpha(0f); - ccHint.setVisibility(View.GONE); - } - } - } - } - - public void showFirstRunCling() { - if (isClingsEnabled() && - !mSharedPrefs.getBoolean(Cling.FIRST_RUN_CLING_DISMISSED_KEY, false) && - !skipCustomClingIfNoAccounts() ) { - // If we're not using the default workspace layout, replace workspace cling - // with a custom workspace cling (usually specified in an overlay) - // For now, only do this on tablets - if (!DISABLE_CUSTOM_CLINGS) { - if (mSharedPrefs.getInt(LauncherProvider.DEFAULT_WORKSPACE_RESOURCE_ID, 0) != 0 && - getResources().getBoolean(R.bool.config_useCustomClings)) { - // Use a custom cling - View cling = findViewById(R.id.workspace_cling); - ViewGroup clingParent = (ViewGroup) cling.getParent(); - int clingIndex = clingParent.indexOfChild(cling); - clingParent.removeViewAt(clingIndex); - View customCling = mInflater.inflate(R.layout.custom_workspace_cling, clingParent, false); - clingParent.addView(customCling, clingIndex); - customCling.setId(R.id.workspace_cling); - } - } - Cling cling = (Cling) findViewById(R.id.first_run_cling); - if (cling != null) { - String sbHintStr = getFirstRunClingSearchBarHint(); - String ccHintStr = getFirstRunCustomContentHint(); - if (!sbHintStr.isEmpty()) { - TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); - sbHint.setText(sbHintStr); - sbHint.setVisibility(View.VISIBLE); - } - setCustomContentHintVisibility(cling, ccHintStr, true, false); - } - initCling(R.id.first_run_cling, 0, false, true); - } else { - removeCling(R.id.first_run_cling); - } - } - /** * Called when the SearchBar hint should be changed. * * @param hint the hint to be displayed in the search bar. */ protected void onSearchBarHintChanged(String hint) { - Cling cling = (Cling) findViewById(R.id.first_run_cling); - if (cling != null && cling.getVisibility() == View.VISIBLE && !hint.isEmpty()) { - TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); - sbHint.setText(hint); - sbHint.setVisibility(View.VISIBLE); - } + mLauncherClings.updateSearchBarHint(hint); } protected String getFirstRunClingSearchBarHint() { @@ -4452,80 +4284,61 @@ public class Launcher extends Activity return ""; } - public void showFirstRunWorkspaceCling() { - // Enable the clings only if they have not been dismissed before - if (isClingsEnabled() && - !mSharedPrefs.getBoolean(Cling.WORKSPACE_CLING_DISMISSED_KEY, false)) { - Cling c = initCling(R.id.workspace_cling, 0, false, true); - - // Set the focused hotseat app if there is one - c.setFocusedHotseatApp(getFirstRunFocusedHotseatAppDrawableId(), - getFirstRunFocusedHotseatAppRank(), - getFirstRunFocusedHotseatAppComponentName(), - getFirstRunFocusedHotseatAppBubbleTitle(), - getFirstRunFocusedHotseatAppBubbleDescription()); - } else { - removeCling(R.id.workspace_cling); - } + public void dismissFirstRunCling(View v) { + mLauncherClings.dismissFirstRunCling(v); } - public Cling showFirstRunFoldersCling() { - // Enable the clings only if they have not been dismissed before - if (isClingsEnabled() && - !mSharedPrefs.getBoolean(Cling.FOLDER_CLING_DISMISSED_KEY, false)) { - Cling cling = initCling(R.id.folder_cling, R.id.cling_scrim, - true, true); - return cling; - } else { - removeCling(R.id.folder_cling); - return null; - } + public void dismissMigrationClingCopyApps(View v) { + mLauncherClings.dismissMigrationClingCopyApps(v); } - protected SharedPreferences getSharedPrefs() { - return mSharedPrefs; + public void dismissMigrationClingUseDefault(View v) { + mLauncherClings.dismissMigrationClingUseDefault(v); } - public boolean isFolderClingVisible() { - Cling cling = (Cling) findViewById(R.id.folder_cling); - if (cling != null) { - return cling.getVisibility() == View.VISIBLE; - } - return false; + public void dismissMigrationWorkspaceCling(View v) { + mLauncherClings.dismissMigrationWorkspaceCling(v); + } + public void dismissWorkspaceCling(View v) { + mLauncherClings.dismissWorkspaceCling(v); + } + public void dismissFolderCling(View v) { + mLauncherClings.dismissFolderCling(v); } - public void dismissFirstRunCling(View v) { - Cling cling = (Cling) findViewById(R.id.first_run_cling); - Runnable cb = new Runnable() { - public void run() { - // Show the workspace cling next - showFirstRunWorkspaceCling(); - } - }; - dismissCling(cling, cb, Cling.FIRST_RUN_CLING_DISMISSED_KEY, - DISMISS_CLING_DURATION, false); - // Fade out the search bar for the workspace cling coming up - mSearchDropTargetBar.hideSearchBar(true); + private boolean shouldRunFirstRunActivity() { + return !ActivityManager.isRunningInTestHarness(); } - public void dismissWorkspaceCling(View v) { - Cling cling = (Cling) findViewById(R.id.workspace_cling); - Runnable cb = null; - if (v == null) { - cb = new Runnable() { - public void run() { - mWorkspace.enterOverviewMode(); - } - }; + + public void showFirstRunActivity() { + if (shouldRunFirstRunActivity() && hasFirstRunActivity() + && !mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false)) { + Intent firstRunIntent = getFirstRunActivity(); + if (firstRunIntent != null) { + startActivity(firstRunIntent); + markFirstRunActivityShown(); + } } - dismissCling(cling, cb, Cling.WORKSPACE_CLING_DISMISSED_KEY, - DISMISS_CLING_DURATION, true); + } - // Fade in the search bar - mSearchDropTargetBar.showSearchBar(true); + private void markFirstRunActivityShown() { + SharedPreferences.Editor editor = mSharedPrefs.edit(); + editor.putBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, true); + editor.apply(); } - public void dismissFolderCling(View v) { - Cling cling = (Cling) findViewById(R.id.folder_cling); - dismissCling(cling, null, Cling.FOLDER_CLING_DISMISSED_KEY, - DISMISS_CLING_DURATION, true); + + void showWorkspaceSearchAndHotseat() { + mWorkspace.setAlpha(1f); + mHotseat.setAlpha(1f); + mPageIndicators.setAlpha(1f); + mSearchDropTargetBar.showSearchBar(false); } + void hideWorkspaceSearchAndHotseat() { + mWorkspace.setAlpha(0f); + mHotseat.setAlpha(0f); + mPageIndicators.setAlpha(0f); + mSearchDropTargetBar.hideSearchBar(false); + } + + public ItemInfo createAppDragInfo(Intent appLaunchIntent) { ResolveInfo ri = getPackageManager().resolveActivity(appLaunchIntent, 0); if (ri == null) { @@ -4667,3 +4480,8 @@ interface LauncherTransitionable { void onLauncherTransitionStep(Launcher l, float t); void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace); } + +interface DebugIntents { + static final String DELETE_DATABASE = "com.android.launcher3.action.DELETE_DATABASE"; + static final String MIGRATE_DATABASE = "com.android.launcher3.action.MIGRATE_DATABASE"; +} diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index d27cedcfc..156befbe0 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -30,9 +30,10 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { private static final String TAG = "LauncherAppState"; private static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs"; + private final AppFilter mAppFilter; + private final BuildInfo mBuildInfo; private LauncherModel mModel; private IconCache mIconCache; - private AppFilter mAppFilter; private WidgetPreviewLoader.CacheDb mWidgetPreviewCacheDb; private boolean mIsScreenLarge; private float mScreenDensity; @@ -87,6 +88,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { mIconCache = new IconCache(sContext); mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class)); + mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class)); mModel = new LauncherModel(this, mIconCache, mAppFilter); // Register intent receivers @@ -237,4 +239,10 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { public void onAvailableSizeChanged(DeviceProfile grid) { Utilities.setIconSize(grid.iconSizePx); } + + public static boolean isDisableAllApps() { + // Returns false on non-dogfood builds. + return getInstance().mBuildInfo.isDogfoodBuild() && + Launcher.isPropertyEnabled(Launcher.DISABLE_ALL_APPS_PROPERTY); + } } diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 2a5ed6961..a081c2191 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -297,7 +297,7 @@ public class LauncherBackupHelper implements BackupHelper { Key key = getKey(Key.FAVORITE, id); keys.add(key); currentIds.add(keyToBackupKey(key)); - if (updateTime > in.t) { + if (updateTime >= in.t) { byte[] blob = packFavorite(cursor); writeRowToBackup(key, blob, out, data); } @@ -365,7 +365,7 @@ public class LauncherBackupHelper implements BackupHelper { Key key = getKey(Key.SCREEN, id); keys.add(key); currentIds.add(keyToBackupKey(key)); - if (updateTime > in.t) { + if (updateTime >= in.t) { byte[] blob = packScreen(cursor); writeRowToBackup(key, blob, out, data); } diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java new file mode 100644 index 000000000..541eaddd0 --- /dev/null +++ b/src/com/android/launcher3/LauncherClings.java @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2008 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; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.ActivityManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.UserManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; +import android.widget.TextView; + +class LauncherClings { + private static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed"; + private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed"; + private static final String MIGRATION_WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed"; + private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed"; + private static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed"; + + private static final boolean DISABLE_CLINGS = false; + private static final boolean DISABLE_CUSTOM_CLINGS = true; + + private static final int SHOW_CLING_DURATION = 250; + private static final int DISMISS_CLING_DURATION = 200; + + private Launcher mLauncher; + private LayoutInflater mInflater; + private HideFromAccessibilityHelper mHideFromAccessibilityHelper + = new HideFromAccessibilityHelper(); + + /** Ctor */ + public LauncherClings(Launcher launcher) { + mLauncher = launcher; + mInflater = mLauncher.getLayoutInflater(); + } + + /** Initializes a cling */ + private Cling initCling(int clingId, int scrimId, boolean animate, + boolean dimNavBarVisibilty) { + Cling cling = (Cling) mLauncher.findViewById(clingId); + View scrim = null; + if (scrimId > 0) { + scrim = mLauncher.findViewById(R.id.cling_scrim); + } + if (cling != null) { + cling.init(mLauncher, scrim); + cling.show(animate, SHOW_CLING_DURATION); + + if (dimNavBarVisibilty) { + cling.setSystemUiVisibility(cling.getSystemUiVisibility() | + View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + } + return cling; + } + + /** Returns whether the clings are enabled or should be shown */ + private boolean isClingsEnabled() { + if (DISABLE_CLINGS) { + return false; + } + + // For now, limit only to phones + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + if (grid.isTablet()) { + return false; + } + if (grid.isLandscape) { + return false; + } + + // disable clings when running in a test harness + if(ActivityManager.isRunningInTestHarness()) return false; + + // Disable clings for accessibility when explore by touch is enabled + final AccessibilityManager a11yManager = (AccessibilityManager) mLauncher.getSystemService( + Launcher.ACCESSIBILITY_SERVICE); + if (a11yManager.isTouchExplorationEnabled()) { + return false; + } + + // Restricted secondary users (child mode) will potentially have very few apps + // seeded when they start up for the first time. Clings won't work well with that + boolean supportsLimitedUsers = + android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; + Account[] accounts = AccountManager.get(mLauncher).getAccounts(); + if (supportsLimitedUsers && accounts.length == 0) { + UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE); + Bundle restrictions = um.getUserRestrictions(); + if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { + return false; + } + } + return true; + } + + /** Returns whether the folder cling is visible. */ + public boolean isFolderClingVisible() { + Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling); + if (cling != null) { + return cling.getVisibility() == View.VISIBLE; + } + return false; + } + + private boolean skipCustomClingIfNoAccounts() { + Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling); + boolean customCling = cling.getDrawIdentifier().equals("workspace_custom"); + if (customCling) { + AccountManager am = AccountManager.get(mLauncher); + if (am == null) return false; + Account[] accounts = am.getAccountsByType("com.google"); + return accounts.length == 0; + } + return false; + } + + /** Updates the first run cling custom content hint */ + private void setCustomContentHintVisibility(Cling cling, String ccHintStr, boolean visible, + boolean animate) { + final TextView ccHint = (TextView) cling.findViewById(R.id.custom_content_hint); + if (ccHint != null) { + if (visible && !ccHintStr.isEmpty()) { + ccHint.setText(ccHintStr); + ccHint.setVisibility(View.VISIBLE); + if (animate) { + ccHint.setAlpha(0f); + ccHint.animate().alpha(1f) + .setDuration(SHOW_CLING_DURATION) + .start(); + } else { + ccHint.setAlpha(1f); + } + } else { + if (animate) { + ccHint.animate().alpha(0f) + .setDuration(SHOW_CLING_DURATION) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + ccHint.setVisibility(View.GONE); + } + }) + .start(); + } else { + ccHint.setAlpha(0f); + ccHint.setVisibility(View.GONE); + } + } + } + } + + /** Updates the first run cling custom content hint */ + public void updateCustomContentHintVisibility() { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + String ccHintStr = mLauncher.getFirstRunCustomContentHint(); + + if (mLauncher.getWorkspace().hasCustomContent()) { + // Show the custom content hint if ccHintStr is not empty + if (cling != null) { + setCustomContentHintVisibility(cling, ccHintStr, true, true); + } + } else { + // Hide the custom content hint + if (cling != null) { + setCustomContentHintVisibility(cling, ccHintStr, false, true); + } + } + } + + /** Updates the first run cling search bar hint. */ + public void updateSearchBarHint(String hint) { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + if (cling != null && cling.getVisibility() == View.VISIBLE && !hint.isEmpty()) { + TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); + sbHint.setText(hint); + sbHint.setVisibility(View.VISIBLE); + } + } + + /** Shows the first run cling */ + public void showFirstRunCling() { + SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); + if (isClingsEnabled() && + !sharedPrefs.getBoolean(FIRST_RUN_CLING_DISMISSED_KEY, false) && + !skipCustomClingIfNoAccounts() ) { + + + // If we're not using the default workspace layout, replace workspace cling + // with a custom workspace cling (usually specified in an overlay) + // For now, only do this on tablets + if (!DISABLE_CUSTOM_CLINGS) { + if (sharedPrefs.getInt(LauncherProvider.DEFAULT_WORKSPACE_RESOURCE_ID, 0) != 0 && + mLauncher.getResources().getBoolean(R.bool.config_useCustomClings)) { + // Use a custom cling + View cling = mLauncher.findViewById(R.id.workspace_cling); + ViewGroup clingParent = (ViewGroup) cling.getParent(); + int clingIndex = clingParent.indexOfChild(cling); + clingParent.removeViewAt(clingIndex); + View customCling = mInflater.inflate(R.layout.custom_workspace_cling, + clingParent, false); + clingParent.addView(customCling, clingIndex); + customCling.setId(R.id.workspace_cling); + } + } + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + if (cling != null) { + String sbHintStr = mLauncher.getFirstRunClingSearchBarHint(); + String ccHintStr = mLauncher.getFirstRunCustomContentHint(); + if (!sbHintStr.isEmpty()) { + TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); + sbHint.setText(sbHintStr); + sbHint.setVisibility(View.VISIBLE); + } + setCustomContentHintVisibility(cling, ccHintStr, true, false); + } + initCling(R.id.first_run_cling, 0, false, true); + } else { + removeCling(R.id.first_run_cling); + } + } + + public void showMigrationCling() { + // Enable the clings only if they have not been dismissed before + if (isClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( + MIGRATION_CLING_DISMISSED_KEY, false)) { + mLauncher.hideWorkspaceSearchAndHotseat(); + + Cling c = initCling(R.id.migration_cling, 0, false, true); + c.bringScrimToFront(); + c.bringToFront(); + } else { + removeCling(R.id.migration_cling); + } + } + + public void showMigrationWorkspaceCling() { + // Enable the clings only if they have not been dismissed before + if (isClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( + MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, false)) { + Cling c = initCling(R.id.migration_workspace_cling, 0, false, true); + c.updateMigrationWorkspaceBubblePosition(); + c.bringScrimToFront(); + c.bringToFront(); + } else { + removeCling(R.id.migration_workspace_cling); + } + } + + public void showWorkspaceCling() { + // Enable the clings only if they have not been dismissed before + if (isClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( + WORKSPACE_CLING_DISMISSED_KEY, false)) { + Cling c = initCling(R.id.workspace_cling, 0, false, true); + + // Set the focused hotseat app if there is one + c.setFocusedHotseatApp(mLauncher.getFirstRunFocusedHotseatAppDrawableId(), + mLauncher.getFirstRunFocusedHotseatAppRank(), + mLauncher.getFirstRunFocusedHotseatAppComponentName(), + mLauncher.getFirstRunFocusedHotseatAppBubbleTitle(), + mLauncher.getFirstRunFocusedHotseatAppBubbleDescription()); + } else { + removeCling(R.id.workspace_cling); + } + } + public Cling showFoldersCling() { + SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); + // Enable the clings only if they have not been dismissed before + if (isClingsEnabled() && + !sharedPrefs.getBoolean(FOLDER_CLING_DISMISSED_KEY, false) && + !sharedPrefs.getBoolean(Launcher.USER_HAS_MIGRATED, false)) { + Cling cling = initCling(R.id.folder_cling, R.id.cling_scrim, + true, true); + return cling; + } else { + removeCling(R.id.folder_cling); + return null; + } + } + + + /** Removes the cling outright from the DragLayer */ + private void removeCling(int id) { + final View cling = mLauncher.findViewById(id); + if (cling != null) { + final ViewGroup parent = (ViewGroup) cling.getParent(); + parent.post(new Runnable() { + @Override + public void run() { + parent.removeView(cling); + } + }); + mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer()); + } + } + + /** Hides the specified Cling */ + private void dismissCling(final Cling cling, final Runnable postAnimationCb, + final String flag, int duration, boolean restoreNavBarVisibilty) { + // To catch cases where siblings of top-level views are made invisible, just check whether + // the cling is directly set to GONE before dismissing it. + if (cling != null && cling.getVisibility() != View.GONE) { + final Runnable cleanUpClingCb = new Runnable() { + public void run() { + cling.cleanup(); + SharedPreferences.Editor editor = mLauncher.getSharedPrefs().edit(); + editor.putBoolean(flag, true); + editor.apply(); + if (postAnimationCb != null) { + postAnimationCb.run(); + } + } + }; + if (duration <= 0) { + cleanUpClingCb.run(); + } else { + cling.hide(duration, cleanUpClingCb); + } + mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer()); + + if (restoreNavBarVisibilty) { + cling.setSystemUiVisibility(cling.getSystemUiVisibility() & + ~View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + } + } + + public void dismissFirstRunCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + Runnable cb = new Runnable() { + public void run() { + // Show the workspace cling next + showWorkspaceCling(); + } + }; + dismissCling(cling, cb, FIRST_RUN_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, false); + + // Fade out the search bar for the workspace cling coming up + mLauncher.getSearchBar().hideSearchBar(true); + } + + private void dismissMigrationCling() { + mLauncher.showWorkspaceSearchAndHotseat(); + Runnable dismissCb = new Runnable() { + public void run() { + Cling cling = (Cling) mLauncher.findViewById(R.id.migration_cling); + Runnable cb = new Runnable() { + public void run() { + // Show the migration workspace cling next + showMigrationWorkspaceCling(); + } + }; + dismissCling(cling, cb, WORKSPACE_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, true); + } + }; + mLauncher.getWorkspace().post(dismissCb); + } + + private void dismissAnyWorkspaceCling(Cling cling, View v) { + Runnable cb = null; + if (v == null) { + cb = new Runnable() { + public void run() { + mLauncher.getWorkspace().enterOverviewMode(); + } + }; + } + dismissCling(cling, cb, WORKSPACE_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, true); + + // Fade in the search bar + mLauncher.getSearchBar().showSearchBar(true); + } + + public void dismissMigrationClingCopyApps(View v) { + // Copy the shortcuts from the old database + LauncherModel model = mLauncher.getModel(); + model.resetLoadedState(false, true); + model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE + | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS); + + // Set the flag to skip the folder cling + String spKey = LauncherAppState.getSharedPreferencesKey(); + SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Launcher.USER_HAS_MIGRATED, true); + editor.apply(); + + // Disable the migration cling + dismissMigrationCling(); + } + + public void dismissMigrationClingUseDefault(View v) { + // Clear the workspace + LauncherModel model = mLauncher.getModel(); + model.resetLoadedState(false, true); + model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE); + + // Disable the migration cling + dismissMigrationCling(); + } + + public void dismissMigrationWorkspaceCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.migration_workspace_cling); + dismissAnyWorkspaceCling(cling, v); + } + + public void dismissWorkspaceCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling); + dismissAnyWorkspaceCling(cling, v); + } + + public void dismissFolderCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling); + dismissCling(cling, null, FOLDER_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, true); + } +}
\ No newline at end of file diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index b2cfb2456..d271976a7 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -75,9 +75,15 @@ public class LauncherModel extends BroadcastReceiver { // false = strew non-workspace apps across the workspace on upgrade public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false; + public static final int LOADER_FLAG_NONE = 0; + public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0; + public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1; + private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons private static final long INVALID_SCREEN_ID = -1L; + private final boolean mAppsCanBeOnRemoveableStorage; + private final boolean mOldContentProviderExists; private final LauncherAppState mApp; private final Object mLock = new Object(); @@ -181,9 +187,12 @@ public class LauncherModel extends BroadcastReceiver { } LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) { - final Context context = app.getContext(); + Context context = app.getContext(); + ContentResolver contentResolver = context.getContentResolver(); mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable(); + mOldContentProviderExists = (contentResolver.acquireContentProviderClient( + LauncherSettings.Favorites.OLD_CONTENT_URI) != null); mApp = app; mBgAllAppsList = new AllAppsList(iconCache, appFilter); mIconCache = iconCache; @@ -218,6 +227,10 @@ public class LauncherModel extends BroadcastReceiver { } } + boolean canMigrateFromOldLauncherDb() { + return mOldContentProviderExists; + } + static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy, long screen) { LauncherAppState app = LauncherAppState.getInstance(); @@ -1193,6 +1206,10 @@ public class LauncherModel extends BroadcastReceiver { } public void startLoader(boolean isLaunching, int synchronousBindPage) { + startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE); + } + + public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) { synchronized (mLock) { if (DEBUG_LOADERS) { Log.d(TAG, "startLoader isLaunching=" + isLaunching); @@ -1207,7 +1224,7 @@ public class LauncherModel extends BroadcastReceiver { // If there is already one running, tell it to stop. // also, don't downgrade isLaunching if we're already running isLaunching = isLaunching || stopLoaderLocked(); - mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching); + mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags); if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE && mAllAppsLoaded && mWorkspaceLoaded) { mLoaderTask.runBindSynchronousPage(synchronousBindPage); @@ -1298,13 +1315,15 @@ public class LauncherModel extends BroadcastReceiver { private boolean mIsLoadingAndBindingWorkspace; private boolean mStopped; private boolean mLoadAndBindStepFinished; + private int mFlags; private HashMap<Object, CharSequence> mLabelCache; - LoaderTask(Context context, boolean isLaunching) { + LoaderTask(Context context, boolean isLaunching, int flags) { mContext = context; mIsLaunching = isLaunching; mLabelCache = new HashMap<Object, CharSequence>(); + mFlags = flags; } boolean isLaunching() { @@ -1466,7 +1485,7 @@ public class LauncherModel extends BroadcastReceiver { sBgDbIconCache.clear(); } - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { // Ensure that all the applications that are in the system are // represented on the home screen. if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) { @@ -1651,7 +1670,7 @@ public class LauncherModel extends BroadcastReceiver { } } - /** Returns whether this is an upgradge path */ + /** Returns whether this is an upgrade path */ private boolean loadWorkspace() { // Log to disk Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true); @@ -1669,8 +1688,20 @@ public class LauncherModel extends BroadcastReceiver { int countX = (int) grid.numColumns; int countY = (int) grid.numRows; - // Make sure the default workspace is loaded, if needed - LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0); + if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) { + Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true); + LauncherAppState.getLauncherProvider().deleteDatabase(); + } + + if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) { + // append the user's Launcher2 shortcuts + Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true); + LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts(); + } else { + // Make sure the default workspace is loaded + Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false); + LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0); + } // Check if we need to do any upgrade-path logic // (Includes having just imported default favorites) @@ -2564,7 +2595,7 @@ public class LauncherModel extends BroadcastReceiver { if (added != null) { // Ensure that we add all the workspace applications to the db Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; - if (!AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (!LauncherAppState.isDisableAllApps()) { addAndBindAddedApps(context, new ArrayList<ItemInfo>(), cb, added); } else { final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 28efd0148..7adbadea1 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -55,9 +55,11 @@ import com.android.launcher3.config.ProviderConfig; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; public class LauncherProvider extends ContentProvider { @@ -72,7 +74,7 @@ public class LauncherProvider extends ContentProvider { static final String AUTHORITY = ProviderConfig.AUTHORITY; // Should we attempt to load anything from the com.android.launcher2 provider? - static final boolean IMPORT_LAUNCHER2_DATABASE = true; + static final boolean IMPORT_LAUNCHER2_DATABASE = false; static final String TABLE_FAVORITES = "favorites"; static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens"; @@ -133,6 +135,9 @@ public class LauncherProvider extends ContentProvider { private static long dbInsertAndCheck(DatabaseHelper helper, SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) { + if (values == null) { + throw new RuntimeException("Error: attempting to insert null values"); + } if (!values.containsKey(LauncherSettings.Favorites._ID)) { throw new RuntimeException("Error: attempting to add item without specifying an id"); } @@ -287,8 +292,13 @@ public class LauncherProvider extends ContentProvider { } } + public void migrateLauncher2Shortcuts() { + mOpenHelper.migrateLauncher2Shortcuts(mOpenHelper.getWritableDatabase(), + LauncherSettings.Favorites.OLD_CONTENT_URI); + } + private static int getDefaultWorkspaceResourceId() { - if (AppsCustomizePagedView.DISABLE_ALL_APPS) { + if (LauncherAppState.isDisableAllApps()) { return R.xml.default_workspace_no_all_apps; } else { return R.xml.default_workspace; @@ -306,6 +316,15 @@ public class LauncherProvider extends ContentProvider { return !isTablet && IMPORT_LAUNCHER2_DATABASE; } + public void deleteDatabase() { + // Are you sure? (y/n) + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final String dbFile = db.getPath(); + mOpenHelper.close(); + SQLiteDatabase.deleteDatabase(new File(dbFile)); + mOpenHelper = new DatabaseHelper(getContext()); + } + private static class DatabaseHelper extends SQLiteOpenHelper { private static final String TAG_FAVORITES = "favorites"; private static final String TAG_FAVORITE = "favorite"; @@ -1431,6 +1450,209 @@ public class LauncherProvider extends ContentProvider { } return id; } + + public void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) { + final ContentResolver resolver = mContext.getContentResolver(); + Cursor c = null; + int count = 0; + int curScreen = 0; + + try { + c = resolver.query(uri, null, null, null, "title ASC"); + } catch (Exception e) { + // Ignore + } + + + // We already have a favorites database in the old provider + if (c != null) { + try { + if (c.getCount() > 0) { + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); + final int intentIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int titleIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + final int iconTypeIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE); + final int iconIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON); + final int iconPackageIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE); + final int iconResourceIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE); + final int containerIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER); + final int itemTypeIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + 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 uriIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); + final int displayModeIndex + = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE); + + int i = 0; + int curX = 0; + int curY = 0; + + final LauncherAppState app = LauncherAppState.getInstance(); + final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + final int width = (int) grid.numColumns; + final int height = (int) grid.numRows; + final int hotseatWidth = (int) grid.numHotseatIcons; + + final HashSet<String> seenIntents = new HashSet<String>(c.getCount()); + + final ContentValues[] rows = new ContentValues[c.getCount()]; + + while (c.moveToNext()) { + final int itemType = c.getInt(itemTypeIndex); + if (itemType != Favorites.ITEM_TYPE_APPLICATION + && itemType != Favorites.ITEM_TYPE_SHORTCUT + && itemType != Favorites.ITEM_TYPE_FOLDER) { + continue; + } + + final int cellX = c.getInt(cellXIndex); + final int cellY = c.getInt(cellYIndex); + final int screen = c.getInt(screenIndex); + int container = c.getInt(containerIndex); + final String intentStr = c.getString(intentIndex); + Launcher.addDumpLog(TAG, "migrating \"" + + c.getString(titleIndex) + "\": " + intentStr, true); + + if (itemType != Favorites.ITEM_TYPE_FOLDER) { + if (TextUtils.isEmpty(intentStr)) { + // no intent? no icon + Launcher.addDumpLog(TAG, "skipping empty intent", true); + continue; + } else { + try { + // Canonicalize + final Intent intent = Intent.parseUri(intentStr, 0); + // the Play Store sets the package parameter, but Launcher + // does not, so we clear that out to keep them the same + intent.setPackage(null); + final String key = intent.toUri(0); + if (seenIntents.contains(key)) { + Launcher.addDumpLog(TAG, "skipping duplicate", true); + continue; + } else { + seenIntents.add(key); + } + } catch (URISyntaxException e) { + // bogus intent? + Launcher.addDumpLog(TAG, + "skipping invalid intent uri", true); + continue; + } + } + } + + ContentValues values = new ContentValues(c.getColumnCount()); + values.put(LauncherSettings.Favorites._ID, c.getInt(idIndex)); + values.put(LauncherSettings.Favorites.INTENT, intentStr); + values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex)); + values.put(LauncherSettings.Favorites.ICON_TYPE, + c.getInt(iconTypeIndex)); + values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex)); + values.put(LauncherSettings.Favorites.ICON_PACKAGE, + c.getString(iconPackageIndex)); + values.put(LauncherSettings.Favorites.ICON_RESOURCE, + c.getString(iconResourceIndex)); + values.put(LauncherSettings.Favorites.ITEM_TYPE, itemType); + values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1); + values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex)); + values.put(LauncherSettings.Favorites.DISPLAY_MODE, + c.getInt(displayModeIndex)); + + if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT + && screen >= hotseatWidth) { + // no room for you in the hotseat? it's off to the desktop with you + container = Favorites.CONTAINER_DESKTOP; + } + + if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { + // In a folder or in the hotseat, preserve position + values.put(LauncherSettings.Favorites.SCREEN, screen); + values.put(LauncherSettings.Favorites.CELLX, cellX); + values.put(LauncherSettings.Favorites.CELLY, cellY); + } else { + values.put(LauncherSettings.Favorites.SCREEN, curScreen); + values.put(LauncherSettings.Favorites.CELLX, curX); + values.put(LauncherSettings.Favorites.CELLY, curY); + curX = (curX + 1) % width; + if (curX == 0) { + curY = (curY + 1); + } + // Leave the last row of icons blank on screen 0 + if (curScreen == 0 && curY == height - 1 || curY == height) { + curScreen = (int) generateNewScreenId(); + curY = 0; + } + } + + values.put(LauncherSettings.Favorites.CONTAINER, container); + + rows[i++] = values; + } + + if (i > 0) { + db.beginTransaction(); + try { + final int N = rows.length; + for (i = 0; i < N; i++) { + if (rows[i] == null) continue; + if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) + < 0) { + return; + } else { + count++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + db.beginTransaction(); + try { + for (i=0; i<=curScreen; i++) { + final ContentValues values = new ContentValues(); + values.put(LauncherSettings.WorkspaceScreens._ID, i); + values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); + if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, null, values) + < 0) { + return; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + } finally { + c.close(); + } + } + + Launcher.addDumpLog(TAG, "migrated " + count + " icons from Launcher2 into " + + (curScreen+1) + " screens", true); + + // ensure that new screens are created to hold these icons + setFlagJustLoadedOldDb(); + + // Update max IDs; very important since we just grabbed IDs from another database + mMaxItemId = initializeMaxItemId(db); + mMaxScreenId = initializeMaxScreenId(db); + if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId + " mMaxScreenId: " + mMaxScreenId); + } } /** diff --git a/src/com/android/launcher3/OnAlarmListener.java b/src/com/android/launcher3/OnAlarmListener.java new file mode 100644 index 000000000..b5ef83e83 --- /dev/null +++ b/src/com/android/launcher3/OnAlarmListener.java @@ -0,0 +1,5 @@ +package com.android.launcher3; + +public interface OnAlarmListener { + public void onAlarm(Alarm alarm); +} diff --git a/src/com/android/launcher3/WallpaperChangedReceiver.java b/src/com/android/launcher3/WallpaperChangedReceiver.java index 28e41d8a5..2d5612f12 100644 --- a/src/com/android/launcher3/WallpaperChangedReceiver.java +++ b/src/com/android/launcher3/WallpaperChangedReceiver.java @@ -22,6 +22,7 @@ import android.content.Intent; public class WallpaperChangedReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent data) { + LauncherAppState.setApplicationContext(context.getApplicationContext()); LauncherAppState appState = LauncherAppState.getInstance(); appState.onWallpaperChanged(); } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index b6276c0f2..2ce9eb3ad 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -579,7 +579,7 @@ public class Workspace extends SmoothPagedView mDefaultPage = mOriginalDefaultPage + 1; // Update the custom content hint - mLauncher.updateCustomContentHintVisibility(); + mLauncher.getLauncherClings().updateCustomContentHintVisibility(); if (mRestorePage != INVALID_RESTORE_PAGE) { mRestorePage = mRestorePage + 1; } else { @@ -608,7 +608,7 @@ public class Workspace extends SmoothPagedView mDefaultPage = mOriginalDefaultPage - 1; // Update the custom content hint - mLauncher.updateCustomContentHintVisibility(); + mLauncher.getLauncherClings().updateCustomContentHintVisibility(); if (mRestorePage != INVALID_RESTORE_PAGE) { mRestorePage = mRestorePage - 1; } else { |