import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
-import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.PagedView.PageSwitchListener;
import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.allapps.AppSearchManager;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
*/
public class Launcher extends Activity
implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
- View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
- LauncherStateTransitionAnimation.Callbacks {
+ View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {
static final String TAG = "Launcher";
static final boolean LOGD = false;
- // Temporary flag
- static final boolean DISABLE_ALL_APPS_SEARCH_INTEGRATION = true;
-
static final boolean PROFILE_STARTUP = false;
static final boolean DEBUG_WIDGETS = true;
static final boolean DEBUG_STRICT_MODE = false;
private static final String QSB_WIDGET_ID = "qsb_widget_id";
private static final String QSB_WIDGET_PROVIDER = "qsb_widget_provider";
+ // Item id to use for QSB widget.
+ private static final int QSB_ITEM_ID = -1;
public static final String USER_HAS_MIGRATED = "launcher.user_migrated_from_old_data";
private final BroadcastReceiver mCloseSystemDialogsReceiver
= new CloseSystemDialogsIntentReceiver();
- private final ContentObserver mWidgetObserver = new AppWidgetResetObserver();
private LayoutInflater mInflater;
private ViewGroup mOverviewPanel;
private View mAllAppsButton;
+ private View mWidgetsButton;
private SearchDropTargetBar mSearchDropTargetBar;
private boolean mHasFocus = false;
private boolean mAttached = false;
+ private LauncherClings mClings;
+
private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>();
private View.OnTouchListener mHapticFeedbackTouchListener;
}
}
- // TODO: remove this field and call method directly when Launcher3 can depend on M APIs
- private static Method sClipRevealMethod = null;
- static {
- Class<?> activityOptionsClass = ActivityOptions.class;
- try {
- sClipRevealMethod = activityOptionsClass.getDeclaredMethod("makeClipRevealAnimation",
- View.class, int.class, int.class, int.class, int.class);
- } catch (Exception e) {
- // Earlier version
- }
- }
-
@Thunk Runnable mBuildLayersRunnable = new Runnable() {
public void run() {
if (mWorkspace != null) {
LauncherAppState.setApplicationContext(getApplicationContext());
LauncherAppState app = LauncherAppState.getInstance();
- LauncherAppState.getLauncherProvider().setLauncherProviderChangeListener(this);
// Load configuration-specific DeviceProfile
mDeviceProfile = getResources().getConfiguration().orientation
mDragController = new DragController(this);
mInflater = getLayoutInflater();
- mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, this);
+ mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
mStats = new Stats(this);
setupViews();
mDeviceProfile.layout(this);
- registerContentObservers();
-
lockAllApps();
mSavedState = savedInstanceState;
public boolean setLauncherCallbacks(LauncherCallbacks callbacks) {
mLauncherCallbacks = callbacks;
- mLauncherCallbacks.setLauncherAppsCallback(new Launcher.LauncherAppsCallbacks() {
- @Override
- public void onAllAppsBoundsChanged(Rect bounds) {
- if (LOGD) {
- Log.d(TAG, "onAllAppsBoundsChanged(Rect): " + bounds);
- }
- mAppsView.setFixedBounds(bounds);
- mWidgetsView.setFixedBounds(bounds);
- }
-
- @Override
- public void dismissAllApps() {
- if (!DISABLE_ALL_APPS_SEARCH_INTEGRATION) {
- // Dismiss All Apps if we aren't already paused/invisible
- if (!mPaused) {
- showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true,
- null /* onCompleteRunnable */, false /* notifyLauncherCallbacks */);
- }
- }
- }
-
- @Override
- public void setSearchManager(AppSearchManager manager) {
- mAppsView.setSearchManager(manager);
- }
- });
mLauncherCallbacks.setLauncherSearchCallback(new Launcher.LauncherSearchCallbacks() {
- private boolean mImportanceStored = false;
+ private boolean mWorkspaceImportanceStored = false;
+ private boolean mHotseatImportanceStored = false;
private int mWorkspaceImportanceForAccessibility =
View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
private int mHotseatImportanceForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@Override
public void onSearchOverlayOpened() {
- if (mImportanceStored) {
+ if (mWorkspaceImportanceStored || mHotseatImportanceStored) {
return;
}
// The underlying workspace and hotseat are temporarily suppressed by the search
// overlay. So they sholudn't be accessible.
- mWorkspaceImportanceForAccessibility = mWorkspace.getImportantForAccessibility();
- mHotseatImportanceForAccessibility = mHotseat.getImportantForAccessibility();
- mWorkspace.setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- mHotseat.setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- mImportanceStored = true;
+ if (mWorkspace != null) {
+ mWorkspaceImportanceForAccessibility =
+ mWorkspace.getImportantForAccessibility();
+ mWorkspace.setImportantForAccessibility(
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ mWorkspaceImportanceStored = true;
+ }
+ if (mHotseat != null) {
+ mHotseatImportanceForAccessibility = mHotseat.getImportantForAccessibility();
+ mHotseat.setImportantForAccessibility(
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ mHotseatImportanceStored = true;
+ }
}
@Override
public void onSearchOverlayClosed() {
- mWorkspace.setImportantForAccessibility(mWorkspaceImportanceForAccessibility);
- mHotseat.setImportantForAccessibility(mHotseatImportanceForAccessibility);
- mImportanceStored = false;
+ if (mWorkspaceImportanceStored && mWorkspace != null) {
+ mWorkspace.setImportantForAccessibility(mWorkspaceImportanceForAccessibility);
+ }
+ if (mHotseatImportanceStored && mHotseat != null) {
+ mHotseat.setImportantForAccessibility(mHotseatImportanceForAccessibility);
+ }
+ mWorkspaceImportanceStored = false;
+ mHotseatImportanceStored = false;
}
});
return true;
}
}
+ /**
+ * Updates the bounds of all the overlays to match the new fixed bounds.
+ */
+ public void updateOverlayBounds(Rect newBounds) {
+ mAppsView.setSearchBarBounds(newBounds);
+ mWidgetsView.setSearchBarBounds(newBounds);
+ }
+
/** To be overridden by subclasses to hint to Launcher that we have custom content */
protected boolean hasCustomContentToLeft() {
if (mLauncherCallbacks != null) {
public 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().
- return !mModel.isLoadingWorkspace();
+ return !isWorkspaceLoading();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static int generateViewId() {
- if (Build.VERSION.SDK_INT >= 17) {
+ if (Utilities.ATLEAST_JB_MR1) {
return View.generateViewId();
} else {
// View.generateViewId() is not available. The following fallback logic is a copy
public int getViewIdForItem(ItemInfo info) {
// This cast is safe given the > 2B range for int.
- int itemId = (int) info.id;
+ return getViewIdForItemId((int) info.id);
+ }
+
+ public int getViewIdForItemId(int itemId) {
if (mItemIdToViewId.containsKey(itemId)) {
return mItemIdToViewId.get(itemId);
}
};
if (requestCode == REQUEST_BIND_APPWIDGET) {
+ // This is called only if the user did not previously have permissions to bind widgets
final int appWidgetId = data != null ?
data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
if (resultCode == RESULT_CANCELED) {
} else if (resultCode == RESULT_OK) {
addAppWidgetImpl(appWidgetId, mPendingAddInfo, null,
mPendingAddWidgetInfo, ON_ACTIVITY_RESULT_ANIMATION_DELAY);
+
+ // When the user has granted permission to bind widgets, we should check to see if
+ // we can inflate the default search bar widget.
+ getOrCreateQsbBar();
}
return;
} else if (requestCode == REQUEST_PICK_WALLPAPER) {
}
}
+ /** @Override for MNC */
+ public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onRequestPermissionsResult(requestCode, permissions,
+ grantResults);
+ }
+ }
+
private PendingAddArguments preparePendingAddArgs(int requestCode, Intent data, int
appWidgetId, ItemInfo info) {
PendingAddArguments args = new PendingAddArguments();
// view after launching an app, as they may be depending on the UI to be static to
// switch to another app, otherwise, if it was
showAppsView(false /* animated */, false /* resetListToTop */,
- !launchedFromApp /* updatePredictedApps */);
+ !launchedFromApp /* updatePredictedApps */, false /* focusSearchBar */);
} else if (mOnResumeState == State.WIDGETS) {
showWidgetsView(false, false);
}
mOnResumeState = State.NONE;
- // Restore the apps state if we are in all apps
- if (!Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION) {
- // Otherwise, notify the callbacks if we are in all apps mode
- if (mState == State.APPS) {
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onAllAppsShown();
- }
- }
- }
-
// Background was set to gradient in onPause(), restore to transparent if in all apps.
setWorkspaceBackground(mState == State.WORKSPACE ? WORKSPACE_BACKGROUND_GRADIENT
: WORKSPACE_BACKGROUND_TRANSPARENT);
mPaused = false;
if (mRestoring || mOnResumeNeedsLoad) {
setWorkspaceLoading(true);
+
+ // If we're starting binding all over again, clear any bind calls we'd postponed in
+ // the past (see waitUntilResume) -- we don't need them since we're starting binding
+ // from scratch again
+ mBindOnResumeCallbacks.clear();
+
mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
mRestoring = false;
mOnResumeNeedsLoad = false;
public void forceExitFullImmersion();
}
- public interface LauncherAppsCallbacks {
- /**
- * Updates launcher to the available space that AllApps can take so as not to overlap with
- * any other views.
- */
- public void onAllAppsBoundsChanged(Rect bounds);
-
- /**
- * Called to dismiss all apps if it is showing.
- */
- public void dismissAllApps();
-
- /**
- * Sets the search manager to be used for app search.
- */
- public void setSearchManager(AppSearchManager manager);
- }
-
public interface LauncherSearchCallbacks {
/**
* Called when the search overlay is shown.
}
mOverviewPanel = (ViewGroup) findViewById(R.id.overview_panel);
- View widgetButton = findViewById(R.id.widget_button);
- widgetButton.setOnClickListener(new OnClickListener() {
+ mWidgetsButton = findViewById(R.id.widget_button);
+ mWidgetsButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (!mWorkspace.isSwitchingState()) {
}
}
});
- widgetButton.setOnTouchListener(getHapticFeedbackTouchListener());
+ mWidgetsButton.setOnTouchListener(getHapticFeedbackTouchListener());
View wallpaperButton = findViewById(R.id.wallpaper_button);
wallpaperButton.setOnClickListener(new OnClickListener() {
mSearchDropTargetBar = (SearchDropTargetBar)
mDragLayer.findViewById(R.id.search_drop_target_bar);
- // Setup Apps
+ // Setup Apps and Widgets
mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view);
- if (isAllAppsSearchOverridden()) {
- mAppsView.hideHeaderBar();
- }
-
- // Setup AppsCustomize
mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view);
+ if (mLauncherCallbacks != null && mLauncherCallbacks.getAllAppsSearchBarController() != null) {
+ mAppsView.setSearchBarController(mLauncherCallbacks.getAllAppsSearchBarController());
+ } else {
+ mAppsView.setSearchBarController(mAppsView.newDefaultAppSearchController());
+ }
// Setup the drag controller (drop targets have to be added in reverse order in priority)
dragController.setDragScoller(mWorkspace);
return mAllAppsButton;
}
+ public View getWidgetsButton() {
+ return mWidgetsButton;
+ }
+
/**
* Creates a view representing a shortcut.
*
}
}
- private int[] getSpanForWidget(ComponentName component, int minWidth, int minHeight) {
- Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(this, component, null);
- // We want to account for the extra amount of padding that we are adding to the widget
- // to ensure that it gets the full amount of space that it has requested
- int requiredWidth = minWidth + padding.left + padding.right;
- int requiredHeight = minHeight + padding.top + padding.bottom;
- return CellLayout.rectToCell(this, requiredWidth, requiredHeight, null);
- }
-
- public int[] getSpanForWidget(AppWidgetProviderInfo info) {
- return getSpanForWidget(info.provider, info.minWidth, info.minHeight);
- }
-
- public int[] getMinSpanForWidget(AppWidgetProviderInfo info) {
- return getSpanForWidget(info.provider, info.minResizeWidth, info.minResizeHeight);
- }
-
/**
* Add a widget to the workspace.
*
}
registerReceiver(mReceiver, filter);
FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView());
- setupTransparentSystemBarsForLmp();
+ setupTransparentSystemBarsForLollipop();
mAttached = true;
mVisible = true;
}
/**
- * Sets up transparent navigation and status bars in LMP.
+ * Sets up transparent navigation and status bars in Lollipop.
* This method is a no-op for other platform versions.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
- private void setupTransparentSystemBarsForLmp() {
- if (Utilities.isLmpOrAbove()) {
+ private void setupTransparentSystemBarsForLollipop() {
+ if (Utilities.ATLEAST_LOLLIPOP) {
Window window = getWindow();
window.getAttributes().systemUiVisibility |=
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
return mOverviewPanel;
}
- public SearchDropTargetBar getSearchBar() {
+ public SearchDropTargetBar getSearchDropTargetBar() {
return mSearchDropTargetBar;
}
super.onNewIntent(intent);
// Close the menu
- if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+ Folder openFolder = mWorkspace.getOpenFolder();
+ boolean alreadyOnHome = mHasFocus && ((intent.getFlags() &
+ Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
+ != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+ boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
+ if (isActionMain) {
// also will cancel mWaitingForResult.
closeSystemDialogs();
- final boolean alreadyOnHome = mHasFocus && ((intent.getFlags() &
- Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
- != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-
if (mWorkspace == null) {
// Can be cases where mWorkspace is null, this prevents a NPE
return;
}
- Folder openFolder = mWorkspace.getOpenFolder();
// In all these cases, only animate if we're already on home
mWorkspace.exitWidgetResizeMode();
- boolean moveToDefaultScreen = mLauncherCallbacks != null ?
- mLauncherCallbacks.shouldMoveToDefaultScreenOnHomeIntent() : true;
- if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
- openFolder == null && moveToDefaultScreen) {
- mWorkspace.moveToDefaultScreen(true);
- }
-
closeFolder();
exitSpringLoadedDragMode();
}
}
- if (DEBUG_RESUME_TIME) {
- Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime));
- }
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onNewIntent(intent);
}
+
+ // Defer moving to the default screen until after we callback to the LauncherCallbacks
+ // as slow logic in the callbacks eat into the time the scroller expects for the snapToPage
+ // animation.
+ if (isActionMain) {
+ boolean moveToDefaultScreen = mLauncherCallbacks != null ?
+ mLauncherCallbacks.shouldMoveToDefaultScreenOnHomeIntent() : true;
+ if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
+ openFolder == null && moveToDefaultScreen) {
+ mWorkspace.post(new Runnable() {
+ @Override
+ public void run() {
+ mWorkspace.moveToDefaultScreen(true);
+ }
+ });
+ }
+ }
+
+ if (DEBUG_RESUME_TIME) {
+ Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime));
+ }
}
@Override
TextKeyListener.getInstance().release();
- getContentResolver().unregisterContentObserver(mWidgetObserver);
unregisterReceiver(mCloseSystemDialogsReceiver);
mDragLayer.clearAllResizeFrames();
}
}
+ public void startSearchFromAllApps(View v, Intent searchIntent, String searchQuery) {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.startSearchFromAllApps(searchQuery)) {
+ return;
+ }
+
+ // If not handled, then just start the provided search intent
+ startActivitySafely(v, searchIntent, null);
+ }
+
public boolean isOnCustomContent() {
return mWorkspace.isOnOrMovingToCustomContent();
}
mPendingAddInfo.screenId = -1;
mPendingAddInfo.cellX = mPendingAddInfo.cellY = -1;
mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1;
- mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = -1;
+ mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = 1;
mPendingAddInfo.dropPos = null;
}
sFolders.remove(folder.id);
}
- /**
- * Registers various content observers. The current implementation registers
- * only a favorites observer to keep track of the favorites applications.
- */
- private void registerContentObservers() {
- ContentResolver resolver = getContentResolver();
- resolver.registerContentObserver(LauncherProvider.CONTENT_APPWIDGET_RESET_URI,
- true, mWidgetObserver);
- }
-
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
}
/**
- * Re-listen when widgets are reset.
+ * Re-listen when widget host is reset.
*/
- @Thunk void onAppWidgetReset() {
+ @Override
+ public void onAppWidgetHostReset() {
if (mAppWidgetHost != null) {
mAppWidgetHost.startListening();
}
*/
protected void onClickAllAppsButton(View v) {
if (LOGD) Log.d(TAG, "onClickAllAppsButton");
- if (isAppsViewVisible()) {
- showWorkspace(true);
- } else {
- // Try and refresh the set of predicted apps before we enter launcher
+ if (!isAppsViewVisible()) {
+ showAppsView(true /* animated */, false /* resetListToTop */,
+ true /* updatePredictedApps */, false /* focusSearchBar */);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickAllAppsButton(v);
+ }
+ }
+ }
+
+ protected void onLongClickAllAppsButton(View v) {
+ if (LOGD) Log.d(TAG, "onLongClickAllAppsButton");
+ if (!isAppsViewVisible()) {
showAppsView(true /* animated */, false /* resetListToTop */,
- true /* updatePredictedApps */);
+ true /* updatePredictedApps */, true /* focusSearchBar */);
}
}
throw new IllegalArgumentException("Input must be a FolderIcon");
}
+ // TODO(sunnygoyal): Re-evaluate this code.
FolderIcon folderIcon = (FolderIcon) v;
final FolderInfo info = folderIcon.getFolderInfo();
Folder openFolder = mWorkspace.getFolderForTag(info);
public void updateInteraction(Workspace.State fromState, Workspace.State toState) {
// Only update the interacting state if we are transitioning to/from a view with an
// overlay
- boolean fromStateWithOverlay;
- boolean toStateWithOverlay;
- if (Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION) {
- fromStateWithOverlay = fromState != Workspace.State.NORMAL;
- toStateWithOverlay = toState != Workspace.State.NORMAL;
- } else {
- fromStateWithOverlay = fromState != Workspace.State.NORMAL &&
- fromState != Workspace.State.NORMAL_HIDDEN;
- toStateWithOverlay = toState != Workspace.State.NORMAL &&
- toState != Workspace.State.NORMAL_HIDDEN;
- }
+ boolean fromStateWithOverlay = fromState != Workspace.State.NORMAL;
+ boolean toStateWithOverlay = toState != Workspace.State.NORMAL;
if (toStateWithOverlay) {
onInteractionBegin();
} else if (fromStateWithOverlay) {
Bundle optsBundle = null;
if (useLaunchAnimation) {
ActivityOptions opts = null;
- if (sClipRevealMethod != null) {
- // TODO: call method directly when Launcher3 can depend on M APIs
+ if (Utilities.ATLEAST_MARSHMALLOW) {
int left = 0, top = 0;
int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
if (v instanceof TextView) {
height = bounds.height();
}
}
- try {
- opts = (ActivityOptions) sClipRevealMethod.invoke(null, v,
- left, top, width, height);
- } catch (IllegalAccessException e) {
- Log.d(TAG, "Could not call makeClipRevealAnimation: " + e);
- sClipRevealMethod = null;
- } catch (InvocationTargetException e) {
- Log.d(TAG, "Could not call makeClipRevealAnimation: " + e);
- sClipRevealMethod = null;
- }
- }
- if (opts == null && !Utilities.isLmpOrAbove()) {
+ opts = ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
+ } else if (!Utilities.ATLEAST_LOLLIPOP) {
+ // Below L, we use a scale up animation
opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
v.getMeasuredWidth(), v.getMeasuredHeight());
+ } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
+ // On L devices, we use the device default slide-up transition.
+ // On L MR1 devices, we a custom version of the slide-up transition which
+ // doesn't have the delay present in the device default.
+ opts = ActivityOptions.makeCustomAnimation(this,
+ R.anim.task_open_enter, R.anim.no_anim);
}
optsBundle = opts != null ? opts.toBundle() : null;
}
return false;
}
- private boolean startActivitySafely(View v, Intent intent, Object tag) {
+ public boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha,
scaleX, scaleY);
- if (Utilities.isLmpOrAbove()) {
+ if (Utilities.ATLEAST_LOLLIPOP) {
oa.setInterpolator(new LogDecelerateInterpolator(100, 0));
}
oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration));
if (isWorkspaceLocked()) return false;
if (mState != State.WORKSPACE) return false;
+ if (v == mAllAppsButton) {
+ onLongClickAllAppsButton(v);
+ return true;
+ }
+
if (v instanceof Workspace) {
if (!mWorkspace.isInOverviewMode()) {
if (!mWorkspace.isTouchActive()) {
}
}
- @Override
- public void onStateTransitionHideSearchBar() {
- // Hide the search bar
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.hideSearchBar(false /* animated */);
- }
- }
-
public void showWorkspace(boolean animated) {
- showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null,
- true);
+ showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null);
}
public void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
- onCompleteRunnable, true);
+ onCompleteRunnable);
}
protected void showWorkspace(int snapToPage, boolean animated) {
- showWorkspace(snapToPage, animated, null, true);
+ showWorkspace(snapToPage, animated, null);
}
- void showWorkspace(int snapToPage, boolean animated, Runnable onCompleteRunnable,
- boolean notifyLauncherCallbacks) {
+ void showWorkspace(int snapToPage, boolean animated, Runnable onCompleteRunnable) {
boolean changed = mState != State.WORKSPACE ||
mWorkspace.getState() != Workspace.State.NORMAL;
if (changed) {
- boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
mWorkspace.setVisibility(View.VISIBLE);
- mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL,
- snapToPage, animated, onCompleteRunnable);
-
- // Show the search bar (only animate if we were showing the drop target bar in spring
- // loaded mode)
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.showSearchBar(animated && wasInSpringLoadedMode);
- }
+ mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(),
+ Workspace.State.NORMAL, snapToPage, animated, onCompleteRunnable);
// Set focus to the AppsCustomize button
if (mAllAppsButton != null) {
// Send an accessibility event to announce the context change
getWindow().getDecorView()
.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- if (notifyLauncherCallbacks) {
- // Dismiss all apps when the workspace is shown
- if (!Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION && mLauncherCallbacks != null) {
- mLauncherCallbacks.onAllAppsHidden();
- }
- }
}
}
void showOverviewMode(boolean animated) {
mWorkspace.setVisibility(View.VISIBLE);
- mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.OVERVIEW,
+ mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(),
+ Workspace.State.OVERVIEW,
WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
null /* onCompleteRunnable */);
mState = State.WORKSPACE;
/**
* Shows the apps view.
*/
- void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps) {
+ void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps,
+ boolean focusSearchBar) {
if (resetListToTop) {
mAppsView.scrollToTop();
}
if (updatePredictedApps) {
tryAndUpdatePredictedApps();
}
- showAppsOrWidgets(animated, State.APPS);
+ showAppsOrWidgets(State.APPS, animated, focusSearchBar);
}
/**
if (resetPageToZero) {
mWidgetsView.scrollToTop();
}
- showAppsOrWidgets(animated, State.WIDGETS);
+ showAppsOrWidgets(State.WIDGETS, animated, false);
mWidgetsView.post(new Runnable() {
@Override
*/
// TODO: calling method should use the return value so that when {@code false} is returned
// the workspace transition doesn't fall into invalid state.
- private boolean showAppsOrWidgets(boolean animated, State toState) {
+ private boolean showAppsOrWidgets(State toState, boolean animated, boolean focusSearchBar) {
if (mState != State.WORKSPACE && mState != State.APPS_SPRING_LOADED &&
mState != State.WIDGETS_SPRING_LOADED) {
return false;
}
if (toState == State.APPS) {
- mStateTransitionAnimation.startAnimationToAllApps(animated);
- if (!Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION && mLauncherCallbacks != null) {
- mLauncherCallbacks.onAllAppsShown();
- }
+ mStateTransitionAnimation.startAnimationToAllApps(mWorkspace.getState(), animated,
+ focusSearchBar);
} else {
- mStateTransitionAnimation.startAnimationToWidgets(animated);
+ mStateTransitionAnimation.startAnimationToWidgets(mWorkspace.getState(), animated);
}
// Change the state *after* we've called all the transition code
return;
}
- mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.SPRING_LOADED,
+ mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(),
+ Workspace.State.SPRING_LOADED,
WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true /* animated */,
null /* onCompleteRunnable */);
mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
final Runnable onCompleteRunnable) {
if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return;
- if (successfulDrop) {
- // We need to trigger all apps hidden to notify search to update itself before the
- // delayed call to showWorkspace below
- if (!Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION && mLauncherCallbacks != null) {
- mLauncherCallbacks.onAllAppsHidden();
- }
- }
-
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
void exitSpringLoadedDragMode() {
if (mState == State.APPS_SPRING_LOADED) {
showAppsView(true /* animated */, false /* resetListToTop */,
- false /* updatePredictedApps */);
+ false /* updatePredictedApps */, false /* focusSearchBar */);
} else if (mState == State.WIDGETS_SPRING_LOADED) {
showWidgetsView(true, false);
}
*/
private void tryAndUpdatePredictedApps() {
if (mLauncherCallbacks != null) {
- List<ComponentName> apps = mLauncherCallbacks.getPredictedApps();
- if (!apps.isEmpty()) {
+ List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
+ if (apps != null) {
mAppsView.setPredictedApps(apps);
}
}
.commit();
}
+ mAppWidgetHost.setQsbWidgetId(widgetId);
if (widgetId != -1) {
mQsb = mAppWidgetHost.createView(this, widgetId, searchProvider);
mQsb.updateAppWidgetOptions(opts);
mQsb.setPadding(0, 0, 0, 0);
+ mQsb.setId(getViewIdForItemId(QSB_ITEM_ID));
mSearchDropTargetBar.addView(mQsb);
mSearchDropTargetBar.setQsbSearchBar(mQsb);
}
text.add(getString(R.string.all_apps_button_label));
} else if (mState == State.WIDGETS) {
text.add(getString(R.string.widget_button_text));
+ } else if (mWorkspace != null) {
+ text.add(mWorkspace.getCurrentPageDescription());
} else {
text.add(getString(R.string.all_apps_home_button_label));
}
}
/**
- * Receives notifications whenever the appwidgets are reset.
- */
- private class AppWidgetResetObserver extends ContentObserver {
- public AppWidgetResetObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onAppWidgetReset();
- }
- }
-
- /**
* If the activity is currently paused, signal that we need to run the passed Runnable
* in onResume.
*
continue;
}
+ final View view;
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
ShortcutInfo info = (ShortcutInfo) item;
- View shortcut = createShortcut(info);
+ view = createShortcut(info);
/*
* TODO: FIX collision case
}
}
}
-
- workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX,
- item.cellY, 1, 1);
- if (animateIcons) {
- // Animate all the applications up now
- shortcut.setAlpha(0f);
- shortcut.setScaleX(0f);
- shortcut.setScaleY(0f);
- bounceAnims.add(createNewAppBounceAnimation(shortcut, i));
- newShortcutsScreenId = item.screenId;
- }
break;
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
+ view = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(FolderInfo) item, mIconCache);
- workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX,
- item.cellY, 1, 1);
break;
default:
throw new RuntimeException("Invalid Item Type");
}
+
+ workspace.addInScreenFromBind(view, item.container, item.screenId, item.cellX,
+ item.cellY, 1, 1);
+ if (animateIcons) {
+ // Animate all the applications up now
+ view.setAlpha(0f);
+ view.setScaleX(0f);
+ view.setScaleY(0f);
+ bounceAnims.add(createNewAppBounceAnimation(view, i));
+ newShortcutsScreenId = item.screenId;
+ }
}
if (animateIcons) {
if (!mIsSafeModeEnabled
&& ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0)
- && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) {
+ && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
+
if (appWidgetInfo == null) {
if (DEBUG_WIDGETS) {
Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
LauncherModel.deleteItemFromDatabase(this, item);
return;
}
- // Note: This assumes that the id remap broadcast is received before this step.
- // If that is not the case, the id remap will be ignored and user may see the
- // click to setup view.
- PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null);
- pendingInfo.spanX = item.spanX;
- pendingInfo.spanY = item.spanY;
- pendingInfo.minSpanX = item.minSpanX;
- pendingInfo.minSpanY = item.minSpanY;
- Bundle options = null;
- WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
-
- int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
- boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
- newWidgetId, appWidgetInfo, options);
- // TODO consider showing a permission dialog when the widget is clicked.
- if (!success) {
- mAppWidgetHost.deleteAppWidgetId(newWidgetId);
- if (DEBUG_WIDGETS) {
- Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
- + " belongs to component " + item.providerName
- + ", as the launcher is unable to bing a new widget id");
+ // If we do not have a valid id, try to bind an id.
+ if ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0) {
+ // Note: This assumes that the id remap broadcast is received before this step.
+ // If that is not the case, the id remap will be ignored and user may see the
+ // click to setup view.
+ PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null);
+ pendingInfo.spanX = item.spanX;
+ pendingInfo.spanY = item.spanY;
+ pendingInfo.minSpanX = item.minSpanX;
+ pendingInfo.minSpanY = item.minSpanY;
+ Bundle options = null;
+ WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
+
+ int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
+ boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
+ newWidgetId, appWidgetInfo, options);
+
+ // TODO consider showing a permission dialog when the widget is clicked.
+ if (!success) {
+ mAppWidgetHost.deleteAppWidgetId(newWidgetId);
+ if (DEBUG_WIDGETS) {
+ Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
+ + " belongs to component " + item.providerName
+ + ", as the launcher is unable to bing a new widget id");
+ }
+ LauncherModel.deleteItemFromDatabase(this, item);
+ return;
}
- LauncherModel.deleteItemFromDatabase(this, item);
- return;
- }
- item.appWidgetId = newWidgetId;
+ item.appWidgetId = newWidgetId;
- // If the widget has a configure activity, it is still needs to set it up, otherwise
- // the widget is ready to go.
- item.restoreStatus = (appWidgetInfo.configure == null)
- ? LauncherAppWidgetInfo.RESTORE_COMPLETED
- : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+ // If the widget has a configure activity, it is still needs to set it up, otherwise
+ // the widget is ready to go.
+ item.restoreStatus = (appWidgetInfo.configure == null)
+ ? LauncherAppWidgetInfo.RESTORE_COMPLETED
+ : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
- LauncherModel.updateItemInDatabase(this, item);
+ LauncherModel.updateItemInDatabase(this, item);
+ } else if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0)
+ && (appWidgetInfo.configure == null)) {
+ // If the ID is already valid, verify if we need to configure or not.
+ item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
+ LauncherModel.updateItemInDatabase(this, item);
+ }
}
if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
}
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+ item.minSpanX = appWidgetInfo.minSpanX;
+ item.minSpanY = appWidgetInfo.minSpanY;
} else {
appWidgetInfo = null;
PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item,
private boolean canRunNewAppsAnimation() {
long diff = System.currentTimeMillis() - mDragController.getLastGestureUpTime();
- return diff > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000);
+ return diff > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000)
+ && (mClings == null || !mClings.isVisible());
}
private ValueAnimator createNewAppBounceAnimation(View v, int i) {
return mDeviceProfile.getSearchBarBounds(Utilities.isRtl(getResources()));
}
- public void bindSearchablesChanged() {
+ public void bindSearchProviderChanged() {
if (mSearchDropTargetBar == null) {
return;
}
return oriMap[(d.getRotation() + indexOffset) % 4];
}
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void lockScreenOrientation() {
if (mRotationEnabled) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ if (Utilities.ATLEAST_JB_MR2) {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
+ } else {
setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
.getConfiguration().orientation));
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
}
}
}
return null;
}
- /**
- * Returns whether the launcher callbacks overrides search in all apps.
- */
- @Thunk boolean isAllAppsSearchOverridden() {
- if (DISABLE_ALL_APPS_SEARCH_INTEGRATION) {
- return false;
- }
-
- if (mLauncherCallbacks != null) {
- return mLauncherCallbacks.overrideAllAppsSearch();
- }
- return false;
- }
-
private boolean shouldRunFirstRunActivity() {
return !ActivityManager.isRunningInTestHarness() &&
!mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false);
// launcher2). Otherwise, we prompt the user upon started for migration
LauncherClings launcherClings = new LauncherClings(this);
if (launcherClings.shouldShowFirstRunOrMigrationClings()) {
+ mClings = launcherClings;
if (mModel.canMigrateFromOldLauncherDb(this)) {
launcherClings.showMigrationCling();
} else {
if (mWorkspace != null) mWorkspace.setAlpha(1f);
if (mHotseat != null) mHotseat.setAlpha(1f);
if (mPageIndicators != null) mPageIndicators.setAlpha(1f);
- if (mSearchDropTargetBar != null) mSearchDropTargetBar.showSearchBar(false);
+ if (mSearchDropTargetBar != null) mSearchDropTargetBar.animateToState(
+ SearchDropTargetBar.State.SEARCH_BAR, 0);
}
void hideWorkspaceSearchAndHotseat() {
if (mWorkspace != null) mWorkspace.setAlpha(0f);
if (mHotseat != null) mHotseat.setAlpha(0f);
if (mPageIndicators != null) mPageIndicators.setAlpha(0f);
- if (mSearchDropTargetBar != null) mSearchDropTargetBar.hideSearchBar(false);
+ if (mSearchDropTargetBar != null) mSearchDropTargetBar.animateToState(
+ SearchDropTargetBar.State.INVISIBLE, 0);
}
+ // TODO: These method should be a part of LauncherSearchCallback
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ItemInfo createAppDragInfo(Intent appLaunchIntent) {
- // Called from search suggestion, not supported in other profiles.
- final UserHandleCompat myUser = UserHandleCompat.myUserHandle();
+ // Called from search suggestion
+ UserHandleCompat user = null;
+ if (Utilities.ATLEAST_LOLLIPOP) {
+ UserHandle userHandle = appLaunchIntent.getParcelableExtra(Intent.EXTRA_USER);
+ if (userHandle != null) {
+ user = UserHandleCompat.fromUser(userHandle);
+ }
+ }
+ return createAppDragInfo(appLaunchIntent, user);
+ }
+
+ // TODO: This method should be a part of LauncherSearchCallback
+ public ItemInfo createAppDragInfo(Intent intent, UserHandleCompat user) {
+ if (user == null) {
+ user = UserHandleCompat.myUserHandle();
+ }
+
+ // Called from search suggestion, add the profile extra to the intent to ensure that we
+ // can launch it correctly
LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
- LauncherActivityInfoCompat activityInfo = launcherApps.resolveActivity(appLaunchIntent,
- myUser);
+ LauncherActivityInfoCompat activityInfo = launcherApps.resolveActivity(intent, user);
if (activityInfo == null) {
return null;
}
- return new AppInfo(this, activityInfo, myUser, mIconCache);
+ return new AppInfo(this, activityInfo, user, mIconCache);
}
+ // TODO: This method should be a part of LauncherSearchCallback
public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
Bitmap icon) {
- // Called from search suggestion, not supported in other profiles.
- return createShortcutDragInfo(shortcutIntent, caption, icon,
+ return new ShortcutInfo(shortcutIntent, caption, caption, icon,
UserHandleCompat.myUserHandle());
}
- public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
- Bitmap icon, UserHandleCompat user) {
- UserManagerCompat userManager = UserManagerCompat.getInstance(this);
- CharSequence contentDescription = userManager.getBadgedLabelForUser(caption, user);
- return new ShortcutInfo(shortcutIntent, caption, contentDescription, icon, user);
- }
-
- protected void moveWorkspaceToDefaultScreen() {
- mWorkspace.moveToDefaultScreen(false);
- }
-
+ // TODO: This method should be a part of LauncherSearchCallback
public void startDrag(View dragView, ItemInfo dragInfo, DragSource source) {
dragView.setTag(dragInfo);
mWorkspace.onExternalDragStartedWithItem(dragView);
mWorkspace.beginExternalDragShared(dragView, source);
}
+ protected void moveWorkspaceToDefaultScreen() {
+ mWorkspace.moveToDefaultScreen(false);
+ }
+
@Override
public void onPageSwitch(View newPage, int newPageIndex) {
if (mLauncherCallbacks != null) {