summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/launcher3/AppWidgetsRestoredReceiver.java90
-rw-r--r--src/com/android/launcher3/AppsCustomizePagedView.java11
-rw-r--r--src/com/android/launcher3/AppsCustomizeTabHost.java346
-rw-r--r--src/com/android/launcher3/BubbleTextView.java22
-rw-r--r--src/com/android/launcher3/DeleteDropTarget.java2
-rw-r--r--src/com/android/launcher3/DragLayer.java30
-rw-r--r--src/com/android/launcher3/FastBitmapDrawable.java61
-rw-r--r--src/com/android/launcher3/Folder.java13
-rw-r--r--src/com/android/launcher3/FolderIcon.java17
-rw-r--r--src/com/android/launcher3/Hotseat.java4
-rw-r--r--src/com/android/launcher3/Launcher.java376
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetHostView.java26
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetInfo.java22
-rw-r--r--src/com/android/launcher3/LauncherModel.java84
-rw-r--r--src/com/android/launcher3/LauncherProvider.java43
-rw-r--r--src/com/android/launcher3/LogAccelerateInterpolator.java25
-rw-r--r--src/com/android/launcher3/LogDecelerateInterpolator.java26
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java6
-rw-r--r--src/com/android/launcher3/Stats.java10
-rw-r--r--src/com/android/launcher3/Utilities.java49
-rw-r--r--src/com/android/launcher3/Workspace.java226
21 files changed, 926 insertions, 563 deletions
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
new file mode 100644
index 000000000..9fef7f934
--- /dev/null
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -0,0 +1,90 @@
+package com.android.launcher3;
+
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "AppWidgetsRestoredReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
+ int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
+ int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ if (oldIds.length == newIds.length) {
+ restoreAppWidgetIds(context, oldIds, newIds);
+ } else {
+ Log.e(TAG, "Invalid host restored received");
+ }
+ }
+ }
+
+ /**
+ * Updates the app widgets whose id has changed during the restore process.
+ */
+ static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
+ final ContentResolver cr = context.getContentResolver();
+ final List<Integer> idsToRemove = new ArrayList<>();
+ final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
+
+ for (int i = 0; i < oldWidgetIds.length; i++) {
+ Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
+
+ final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
+
+ ContentValues values = new ContentValues();
+ values.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]);
+ values.put(LauncherSettings.Favorites.RESTORED, LauncherModel.isValidProvider(provider)
+ ? LauncherAppWidgetInfo.RESTORE_COMPLETED
+ : LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING);
+
+ String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) };
+
+ int result = cr.update(Favorites.CONTENT_URI, values,
+ "appWidgetId=? and restored=1", widgetIdParams);
+ if (result == 0) {
+ Cursor cursor = cr.query(Favorites.CONTENT_URI,
+ new String[] {Favorites.APPWIDGET_ID},
+ "appWidgetId=?", widgetIdParams, null);
+ try {
+ if (!cursor.moveToFirst()) {
+ // The widget no long exists.
+ idsToRemove.add(newWidgetIds[i]);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+ // Unregister the widget IDs which are not present on the workspace. This could happen
+ // when a widget place holder is removed from workspace, before this method is called.
+ if (!idsToRemove.isEmpty()) {
+ final AppWidgetHost appWidgetHost =
+ new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
+ new AsyncTask<Void, Void, Void>() {
+ public Void doInBackground(Void ... args) {
+ for (Integer id : idsToRemove) {
+ appWidgetHost.deleteAppWidgetId(id);
+ Log.e(TAG, "Widget no longer present, appWidgetId=" + id);
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index 2520b8a12..0e9969697 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -377,8 +377,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
mWidgetSpacingLayout.measure(widthSpec, heightSpec);
- AppsCustomizeTabHost host = (AppsCustomizeTabHost) getTabHost();
- final boolean hostIsTransitioning = host.isTransitioning();
+ final boolean hostIsTransitioning = getTabHost().isInTransition();
// Restore the page
int page = getPageForComponent(mSaveInstanceStateItemIndex);
@@ -1617,12 +1616,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// If we have reset, then we should not continue to restore the previous state
mSaveInstanceStateItemIndex = -1;
- AppsCustomizeTabHost tabHost = getTabHost();
- String tag = tabHost.getCurrentTabTag();
- if (tag != null) {
- if (!tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) {
- tabHost.setCurrentTabFromContent(ContentType.Applications);
- }
+ if (mContentType != ContentType.Applications) {
+ setContentType(ContentType.Applications);
}
if (mCurrentPage != 0) {
diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java
index c6455c2fe..334d8b6f6 100644
--- a/src/com/android/launcher3/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher3/AppsCustomizeTabHost.java
@@ -38,35 +38,20 @@ import android.widget.TextView;
import java.util.ArrayList;
-public class AppsCustomizeTabHost extends TabHost implements LauncherTransitionable,
- TabHost.OnTabChangeListener, Insettable {
+public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
static final String LOG_TAG = "AppsCustomizeTabHost";
private static final String APPS_TAB_TAG = "APPS";
private static final String WIDGETS_TAB_TAG = "WIDGETS";
- private final LayoutInflater mLayoutInflater;
- private ViewGroup mTabs;
- private ViewGroup mTabsContainer;
- private AppsCustomizePagedView mAppsCustomizePane;
- private FrameLayout mAnimationBuffer;
- private LinearLayout mContent;
-
- private boolean mInTransition;
- private boolean mTransitioningToWorkspace;
- private boolean mResetAfterTransition;
- private Runnable mRelayoutAndMakeVisible;
+ private AppsCustomizePagedView mPagedView;
+ private View mContent;
+ private boolean mInTransition = false;
+
private final Rect mInsets = new Rect();
public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
super(context, attrs);
- mLayoutInflater = LayoutInflater.from(context);
- mRelayoutAndMakeVisible = new Runnable() {
- public void run() {
- mTabs.requestLayout();
- mTabsContainer.setAlpha(1f);
- }
- };
}
/**
@@ -76,17 +61,17 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona
* tabs manually).
*/
void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
- setOnTabChangedListener(null);
- onTabChangedStart();
- onTabChangedEnd(type);
- setCurrentTabByTag(getTabTagForContentType(type));
- setOnTabChangedListener(this);
+ mPagedView.setContentType(type);
+ }
+
+ public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
+ setContentTypeImmediate(type);
}
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
- FrameLayout.LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
+ LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
flp.topMargin = insets.top;
flp.bottomMargin = insets.bottom;
flp.leftMargin = insets.left;
@@ -99,212 +84,12 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona
*/
@Override
protected void onFinishInflate() {
- // Setup the tab host
- setup();
-
- final ViewGroup tabsContainer = (ViewGroup) findViewById(R.id.tabs_container);
- final TabWidget tabs = getTabWidget();
- final AppsCustomizePagedView appsCustomizePane = (AppsCustomizePagedView)
- findViewById(R.id.apps_customize_pane_content);
- mTabs = tabs;
- mTabsContainer = tabsContainer;
- mAppsCustomizePane = appsCustomizePane;
- mAnimationBuffer = (FrameLayout) findViewById(R.id.animation_buffer);
- mContent = (LinearLayout) findViewById(R.id.apps_customize_content);
- if (tabs == null || mAppsCustomizePane == null) throw new Resources.NotFoundException();
-
- // Configure the tabs content factory to return the same paged view (that we change the
- // content filter on)
- TabContentFactory contentFactory = new TabContentFactory() {
- public View createTabContent(String tag) {
- return appsCustomizePane;
- }
- };
-
- // Create the tabs
- TextView tabView;
- String label;
- label = getContext().getString(R.string.all_apps_button_label);
- tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
- tabView.setText(label);
- tabView.setContentDescription(label);
- addTab(newTabSpec(APPS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
- label = getContext().getString(R.string.widgets_tab_label);
- tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
- tabView.setText(label);
- tabView.setContentDescription(label);
- addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
- setOnTabChangedListener(this);
-
- // Setup the key listener to jump between the last tab view and the market icon
- AppsCustomizeTabKeyEventListener keyListener = new AppsCustomizeTabKeyEventListener();
- View lastTab = tabs.getChildTabViewAt(tabs.getTabCount() - 1);
- lastTab.setOnKeyListener(keyListener);
- View shopButton = findViewById(R.id.market_button);
- shopButton.setOnKeyListener(keyListener);
-
- // Hide the tab bar until we measure
- mTabsContainer.setAlpha(0f);
+ mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content);
+ mContent = findViewById(R.id.content);
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- boolean remeasureTabWidth = (mTabs.getLayoutParams().width <= 0);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- // Set the width of the tab list to the content width
- if (remeasureTabWidth) {
- int contentWidth = mAppsCustomizePane.getPageContentWidth();
- if (contentWidth > 0 && mTabs.getLayoutParams().width != contentWidth) {
- // Set the width and show the tab bar
- mTabs.getLayoutParams().width = contentWidth;
- mRelayoutAndMakeVisible.run();
- }
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
-
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // If we are mid transitioning to the workspace, then intercept touch events here so we
- // can ignore them, otherwise we just let all apps handle the touch events.
- if (mInTransition && mTransitioningToWorkspace) {
- return true;
- }
- return super.onInterceptTouchEvent(ev);
- };
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Allow touch events to fall through to the workspace if we are transitioning there
- if (mInTransition && mTransitioningToWorkspace) {
- return super.onTouchEvent(event);
- }
-
- // Intercept all touch events up to the bottom of the AppsCustomizePane so they do not fall
- // through to the workspace and trigger showWorkspace()
- if (event.getY() < mAppsCustomizePane.getBottom()) {
- return true;
- }
- return super.onTouchEvent(event);
- }
-
- private void onTabChangedStart() {
- }
-
- private void reloadCurrentPage() {
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage());
- mAppsCustomizePane.requestFocus();
- }
-
- private void onTabChangedEnd(AppsCustomizePagedView.ContentType type) {
- int bgAlpha = (int) (255 * (getResources().getInteger(
- R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f));
- setBackgroundColor(Color.argb(bgAlpha, 0, 0, 0));
- mAppsCustomizePane.setContentType(type);
- }
-
- @Override
- public void onTabChanged(String tabId) {
- final AppsCustomizePagedView.ContentType type = getContentTypeForTabTag(tabId);
-
- // Animate the changing of the tab content by fading pages in and out
- final Resources res = getResources();
- final int duration = res.getInteger(R.integer.config_tabTransitionDuration);
-
- // We post a runnable here because there is a delay while the first page is loading and
- // the feedback from having changed the tab almost feels better than having it stick
- post(new Runnable() {
- @Override
- public void run() {
- if (mAppsCustomizePane.getMeasuredWidth() <= 0 ||
- mAppsCustomizePane.getMeasuredHeight() <= 0) {
- reloadCurrentPage();
- return;
- }
-
- // Take the visible pages and re-parent them temporarily to mAnimatorBuffer
- // and then cross fade to the new pages
- int[] visiblePageRange = new int[2];
- mAppsCustomizePane.getVisiblePages(visiblePageRange);
- if (visiblePageRange[0] == -1 && visiblePageRange[1] == -1) {
- // If we can't get the visible page ranges, then just skip the animation
- reloadCurrentPage();
- return;
- }
- ArrayList<View> visiblePages = new ArrayList<View>();
- for (int i = visiblePageRange[0]; i <= visiblePageRange[1]; i++) {
- visiblePages.add(mAppsCustomizePane.getPageAt(i));
- }
-
- // We want the pages to be rendered in exactly the same way as they were when
- // their parent was mAppsCustomizePane -- so set the scroll on mAnimationBuffer
- // to be exactly the same as mAppsCustomizePane, and below, set the left/top
- // parameters to be correct for each of the pages
- mAnimationBuffer.scrollTo(mAppsCustomizePane.getScrollX(), 0);
-
- // mAppsCustomizePane renders its children in reverse order, so
- // add the pages to mAnimationBuffer in reverse order to match that behavior
- for (int i = visiblePages.size() - 1; i >= 0; i--) {
- View child = visiblePages.get(i);
- if (child instanceof AppsCustomizeCellLayout) {
- ((AppsCustomizeCellLayout) child).resetChildrenOnKeyListeners();
- } else if (child instanceof PagedViewGridLayout) {
- ((PagedViewGridLayout) child).resetChildrenOnKeyListeners();
- }
- PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(false);
- mAppsCustomizePane.removeView(child);
- PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(true);
- mAnimationBuffer.setAlpha(1f);
- mAnimationBuffer.setVisibility(View.VISIBLE);
- LayoutParams p = new FrameLayout.LayoutParams(child.getMeasuredWidth(),
- child.getMeasuredHeight());
- p.setMargins((int) child.getLeft(), (int) child.getTop(), 0, 0);
- mAnimationBuffer.addView(child, p);
- }
-
- // Toggle the new content
- onTabChangedStart();
- onTabChangedEnd(type);
-
- // Animate the transition
- ObjectAnimator outAnim = LauncherAnimUtils.ofFloat(mAnimationBuffer, "alpha", 0f);
- outAnim.addListener(new AnimatorListenerAdapter() {
- private void clearAnimationBuffer() {
- mAnimationBuffer.setVisibility(View.GONE);
- PagedViewWidget.setRecyclePreviewsWhenDetachedFromWindow(false);
- mAnimationBuffer.removeAllViews();
- PagedViewWidget.setRecyclePreviewsWhenDetachedFromWindow(true);
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- clearAnimationBuffer();
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- clearAnimationBuffer();
- }
- });
- ObjectAnimator inAnim = LauncherAnimUtils.ofFloat(mAppsCustomizePane, "alpha", 1f);
- inAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- reloadCurrentPage();
- }
- });
-
- final AnimatorSet animSet = LauncherAnimUtils.createAnimatorSet();
- animSet.playTogether(outAnim, inAnim);
- animSet.setDuration(duration);
- animSet.start();
- }
- });
- }
-
- public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
- setOnTabChangedListener(null);
- setCurrentTabByTag(getTabTagForContentType(type));
- setOnTabChangedListener(this);
+ public String getContentTag() {
+ return getTabTagForContentType(mPagedView.getContentType());
}
/**
@@ -343,44 +128,41 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona
}
void reset() {
- if (mInTransition) {
- // Defer to after the transition to reset
- mResetAfterTransition = true;
- } else {
- // Reset immediately
- mAppsCustomizePane.reset();
- }
+ // Reset immediately
+ mPagedView.reset();
}
- private void enableAndBuildHardwareLayer() {
- // isHardwareAccelerated() checks if we're attached to a window and if that
- // window is HW accelerated-- we were sometimes not attached to a window
- // and buildLayer was throwing an IllegalStateException
- if (isHardwareAccelerated()) {
- // Turn on hardware layers for performance
- setLayerType(LAYER_TYPE_HARDWARE, null);
-
- // force building the layer, so you don't get a blip early in an animation
- // when the layer is created layer
- buildLayer();
+ public void onWindowVisible() {
+ if (getVisibility() == VISIBLE) {
+ mContent.setVisibility(VISIBLE);
+ // We unload the widget previews when the UI is hidden, so need to reload pages
+ // Load the current page synchronously, and the neighboring pages asynchronously
+ mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
+ mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
}
}
+ public void onTrimMemory() {
+ mContent.setVisibility(GONE);
+ // Clear the widget pages of all their subviews - this will trigger the widget previews
+ // to delete their bitmaps
+ mPagedView.clearAllWidgetPages();
+ }
+
@Override
public View getContent() {
- View appsCustomizeContent = mAppsCustomizePane.getContent();
- if (appsCustomizeContent != null) {
- return appsCustomizeContent;
- }
- return mContent;
+ return mPagedView;
+ }
+
+ public boolean isInTransition() {
+ return mInTransition;
}
/* LauncherTransitionable overrides */
@Override
public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- mAppsCustomizePane.onLauncherTransitionPrepare(l, animated, toWorkspace);
+ mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace);
mInTransition = true;
- mTransitioningToWorkspace = toWorkspace;
if (toWorkspace) {
// Going from All Apps -> Workspace
@@ -391,52 +173,43 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona
// Make sure the current page is loaded (we start loading the side pages after the
// transition to prevent slowing down the animation)
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage(), true);
- }
-
- if (mResetAfterTransition) {
- mAppsCustomizePane.reset();
- mResetAfterTransition = false;
+ // TODO: revisit this
+ mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
}
}
@Override
public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- mAppsCustomizePane.onLauncherTransitionStart(l, animated, toWorkspace);
- if (animated) {
+ mPagedView.onLauncherTransitionStart(l, animated, toWorkspace);
+ if (animated && !Utilities.isLmp()) {
enableAndBuildHardwareLayer();
}
-
- // Dismiss the workspace cling
- l.getLauncherClings().dismissWorkspaceCling(null);
}
@Override
public void onLauncherTransitionStep(Launcher l, float t) {
- mAppsCustomizePane.onLauncherTransitionStep(l, t);
+ mPagedView.onLauncherTransitionStep(l, t);
}
@Override
public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- mAppsCustomizePane.onLauncherTransitionEnd(l, animated, toWorkspace);
+ mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace);
mInTransition = false;
- if (animated) {
+ if (animated && !Utilities.isLmp()) {
setLayerType(LAYER_TYPE_NONE, null);
}
if (!toWorkspace) {
- // Show the all apps cling (if not already shown)
- mAppsCustomizePane.showAllAppsCling();
// Make sure adjacent pages are loaded (we wait until after the transition to
// prevent slowing down the animation)
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage());
+ mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
// Opening apps, need to announce what page we are on.
AccessibilityManager am = (AccessibilityManager)
getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
if (am.isEnabled()) {
// Notify the user when the page changes
- announceForAccessibility(mAppsCustomizePane.getCurrentPageDescription());
+ announceForAccessibility(mPagedView.getCurrentPageDescription());
}
// Going from Workspace -> All Apps
@@ -469,24 +242,19 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona
}
}
- public void onWindowVisible() {
- if (getVisibility() == VISIBLE) {
- mContent.setVisibility(VISIBLE);
- // We unload the widget previews when the UI is hidden, so need to reload pages
- // Load the current page synchronously, and the neighboring pages asynchronously
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage(), true);
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage());
+ private void enableAndBuildHardwareLayer() {
+ // isHardwareAccelerated() checks if we're attached to a window and if that
+ // window is HW accelerated-- we were sometimes not attached to a window
+ // and buildLayer was throwing an IllegalStateException
+ if (isHardwareAccelerated()) {
+ // Turn on hardware layers for performance
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+
+ // force building the layer, so you don't get a blip early in an animation
+ // when the layer is created layer
+ buildLayer();
}
}
- public void onTrimMemory() {
- mContent.setVisibility(GONE);
- // Clear the widget pages of all their subviews - this will trigger the widget previews
- // to delete their bitmaps
- mAppsCustomizePane.clearAllWidgetPages();
- }
- boolean isTransitioning() {
- return mInTransition;
- }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 3f619a812..ffa7ec37e 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -51,8 +51,6 @@ public class BubbleTextView extends TextView {
private static final boolean DEBUG = false;
- private int mPrevAlpha = -1;
-
private HolographicOutlineHelper mOutlineHelper;
private final Canvas mTempCanvas = new Canvas();
private final Rect mTempRect = new Rect();
@@ -124,14 +122,22 @@ public class BubbleTextView extends TextView {
}
}
- public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {
+ public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
+ boolean setDefaultPadding) {
Bitmap b = info.getIcon(iconCache);
LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- Drawable iconDrawable = Utilities.createIconDrawable(b);
+ FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
+ if (info.isDisabled) {
+ iconDrawable.setSaturation(0);
+ iconDrawable.setBrightness(20);
+ }
+
setCompoundDrawables(null, iconDrawable, null, null);
- setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
+ if (setDefaultPadding) {
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
+ }
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
}
@@ -417,10 +423,6 @@ public class BubbleTextView extends TextView {
@Override
protected boolean onSetAlpha(int alpha) {
- if (mPrevAlpha != alpha) {
- mPrevAlpha = alpha;
- super.onSetAlpha(alpha);
- }
return true;
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 3d45432c2..4c3388e05 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -326,7 +326,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
- if (appWidgetHost != null) {
+ if ((appWidgetHost != null) && launcherAppWidgetInfo.isWidgetIdValid()) {
// Deleting an app widget ID is a void call but writes to disk before returning
// to the caller...
new AsyncTask<Void, Void, Void>() {
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index c54db0127..8bcc407d6 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -77,6 +77,10 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
private int mTopViewIndex;
private int mChildCountOnLastUpdate = -1;
+ // Darkening scrim
+ private Drawable mBackground;
+ private float mBackgroundAlpha = 0;
+
/**
* Used to create a new DragLayer from XML.
*
@@ -91,8 +95,10 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
setChildrenDrawingOrderEnabled(true);
setOnHierarchyChangeListener(this);
- mLeftHoverDrawable = getResources().getDrawable(R.drawable.page_hover_left_holo);
- mRightHoverDrawable = getResources().getDrawable(R.drawable.page_hover_right_holo);
+ final Resources res = getResources();
+ mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left_holo);
+ mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right_holo);
+ mBackground = res.getDrawable(R.drawable.apps_customize_bg);
}
public void setup(Launcher launcher, DragController controller) {
@@ -862,8 +868,17 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
@Override
protected void dispatchDraw(Canvas canvas) {
+ // Draw the background gradient below children.
+ if (mBackground != null && mBackgroundAlpha > 0.0f) {
+ int alpha = (int) (mBackgroundAlpha * 255);
+ mBackground.setAlpha(alpha);
+ mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ mBackground.draw(canvas);
+ }
+
super.dispatchDraw(canvas);
+ // Draw screen hover indicators above children.
if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) {
Workspace workspace = mLauncher.getWorkspace();
int width = getMeasuredWidth();
@@ -887,6 +902,17 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
}
}
+ public void setBackgroundAlpha(float alpha) {
+ if (alpha != mBackgroundAlpha) {
+ mBackgroundAlpha = alpha;
+ invalidate();
+ }
+ }
+
+ public float getBackgroundAlpha() {
+ return mBackgroundAlpha;
+ }
+
public void setTouchCompleteListener(TouchCompleteListener listener) {
mTouchCompleteListener = listener;
}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 85e90202b..ef8d0973d 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -19,15 +19,24 @@ package com.android.launcher3;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
class FastBitmapDrawable extends Drawable {
+
+ private static final ColorMatrix sTempSaturationMatrix = new ColorMatrix();
+ private static final ColorMatrix sTempBrightnessMatrix = new ColorMatrix();
+
+ private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
private Bitmap mBitmap;
private int mAlpha;
- private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+
+ private float mSatutation = 1;
+ private int mBrightness = 0;
FastBitmapDrawable(Bitmap b) {
mAlpha = 255;
@@ -44,7 +53,7 @@ class FastBitmapDrawable extends Drawable {
@Override
public void setColorFilter(ColorFilter cf) {
- mPaint.setColorFilter(cf);
+ // No op
}
@Override
@@ -58,6 +67,7 @@ class FastBitmapDrawable extends Drawable {
mPaint.setAlpha(alpha);
}
+ @Override
public void setFilterBitmap(boolean filterBitmap) {
mPaint.setFilterBitmap(filterBitmap);
mPaint.setAntiAlias(filterBitmap);
@@ -90,4 +100,51 @@ class FastBitmapDrawable extends Drawable {
public Bitmap getBitmap() {
return mBitmap;
}
+
+ public float getSaturation() {
+ return mSatutation;
+ }
+
+ public void setSaturation(float saturation) {
+ mSatutation = saturation;
+ updateFilter();
+ }
+
+ public int getBrightness() {
+ return mBrightness;
+ }
+
+ public void addBrightness(int amount) {
+ mBrightness += amount;
+ updateFilter();
+ }
+
+ public void setBrightness(int brightness) {
+ mBrightness = brightness;
+ updateFilter();
+ }
+
+ private void updateFilter() {
+ if (mSatutation != 1 || mBrightness != 0) {
+ sTempSaturationMatrix.setSaturation(mSatutation);
+
+ if (mBrightness != 0) {
+ // Brightness: C-new = C-old*(1-amount) + amount
+ float scale = 1 - mBrightness / 255.0f;
+ sTempBrightnessMatrix.setScale(scale, scale, scale, 1);
+ float[] array = sTempBrightnessMatrix.getArray();
+
+ // Add the amount to RGB components of the matrix, as per the above formula.
+ // Fifth elements in the array correspond to the constant being added to
+ // red, blue, green, and alpha channel respectively.
+ array[4] = mBrightness;
+ array[9] = mBrightness;
+ array[14] = mBrightness;
+ sTempSaturationMatrix.preConcat(sTempBrightnessMatrix);
+ }
+ mPaint.setColorFilter(new ColorMatrixColorFilter(sTempSaturationMatrix));
+ } else {
+ mPaint.setColorFilter(null);
+ }
+ }
}
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 47c8a4a0f..655e5c368 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -566,15 +566,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
protected View createAndAddShortcut(ShortcutInfo item) {
- final TextView textView =
- (TextView) mInflater.inflate(R.layout.folder_application, this, false);
- textView.setCompoundDrawables(null,
- Utilities.createIconDrawable(item.getIcon(mIconCache)), null, null);
- textView.setText(item.title);
- if (item.contentDescription != null) {
- textView.setContentDescription(item.contentDescription);
- }
- textView.setTag(item);
+ final BubbleTextView textView =
+ (BubbleTextView) mInflater.inflate(R.layout.folder_application, this, false);
+ textView.applyFromShortcutInfo(item, mIconCache, false);
+
textView.setOnClickListener(this);
textView.setOnLongClickListener(this);
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 4f674f55a..5b49fb87a 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -133,7 +133,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
final Workspace workspace = (Workspace) cellLayout.getParent();
- return !workspace.isSmall();
+ return !workspace.workspaceInModalState();
}
static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
@@ -580,10 +580,17 @@ public class FolderIcon extends FrameLayout implements FolderListener {
if (d != null) {
mOldBounds.set(d.getBounds());
d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
- d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
- PorterDuff.Mode.SRC_ATOP);
- d.draw(canvas);
- d.clearColorFilter();
+ if (d instanceof FastBitmapDrawable) {
+ FastBitmapDrawable fd = (FastBitmapDrawable) d;
+ fd.addBrightness(params.overlayAlpha);
+ d.draw(canvas);
+ fd.addBrightness(-params.overlayAlpha);
+ } else {
+ d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
+ PorterDuff.Mode.SRC_ATOP);
+ d.draw(canvas);
+ d.clearColorFilter();
+ }
d.setBounds(mOldBounds);
}
canvas.restore();
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 2d171238f..79cac8f64 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -167,7 +167,7 @@ public class Hotseat extends FrameLayout {
int y = getCellYFromOrder(mAllAppsButtonRank);
CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
lp.canReorder = false;
- mContent.addViewToCellLayout(allAppsButton, -1, 0, lp, true);
+ mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
}
}
@@ -175,7 +175,7 @@ public class Hotseat extends FrameLayout {
public boolean onInterceptTouchEvent(MotionEvent ev) {
// We don't want any clicks to go through to the hotseat unless the workspace is in
// the normal state.
- if (mLauncher.getWorkspace().isSmall()) {
+ if (mLauncher.getWorkspace().workspaceInModalState()) {
return true;
}
return false;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 951b5d459..65f9cbee8 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -82,28 +82,36 @@ import android.view.Menu;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
+import android.view.ViewAnimationUtils;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Advanceable;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
+
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.PagedView.PageSwitchListener;
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.DropTarget.DragObject;
import com.android.launcher3.PagedView.PageSwitchListener;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -198,7 +206,6 @@ public class Launcher extends Activity
// Type: int[]
private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids";
-
static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed";
static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed";
@@ -218,6 +225,8 @@ public class Launcher extends Activity
private State mState = State.WORKSPACE;
private AnimatorSet mStateAnimation;
+ private boolean mIsSafeModeEnabled;
+
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;
@@ -421,6 +430,7 @@ public class Launcher extends Activity
// the LauncherApplication should call this, but in case of Instrumentation it might not be present yet
mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),
Context.MODE_PRIVATE);
+ mIsSafeModeEnabled = getPackageManager().isSafeMode();
mModel = app.setLauncher(this);
mIconCache = app.getIconCache();
mIconCache.flushInvalidIcons(grid);
@@ -1395,7 +1405,7 @@ public class Launcher extends Activity
*/
View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
- favorite.applyFromShortcutInfo(info, mIconCache);
+ favorite.applyFromShortcutInfo(info, mIconCache, true);
favorite.setOnClickListener(this);
return favorite;
}
@@ -2775,6 +2785,7 @@ public class Launcher extends Activity
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
+ // TODO Component can be null when shortcuts are supported for secondary user
launcherApps.startActivityForProfile(intent.getComponent(), user,
intent.getSourceBounds(), optsBundle);
}
@@ -2791,6 +2802,10 @@ public class Launcher extends Activity
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();
+ return false;
+ }
try {
success = startActivity(v, intent, tag);
} catch (ActivityNotFoundException e) {
@@ -3146,6 +3161,7 @@ public class Launcher extends Activity
AppsCustomizePagedView.ContentType contentType = mAppsCustomizeContent.getContentType();
showAppsCustomizeHelper(animated, springLoaded, contentType);
}
+
private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded,
final AppsCustomizePagedView.ContentType contentType) {
if (mStateAnimation != null) {
@@ -3153,10 +3169,15 @@ public class Launcher extends Activity
mStateAnimation.cancel();
mStateAnimation = null;
}
+
+ boolean material = Utilities.isLmp();
+
final Resources res = getResources();
final int duration = res.getInteger(R.integer.config_appsCustomizeZoomInTime);
final int fadeDuration = res.getInteger(R.integer.config_appsCustomizeFadeInTime);
+ final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
+
final float scale = (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
final View fromView = mWorkspace;
final AppsCustomizeTabHost toView = mAppsCustomizeTabHost;
@@ -3165,9 +3186,10 @@ public class Launcher extends Activity
setPivotsForZoom(toView, scale);
- // Shrink workspaces away if going to AppsCustomize from workspace
+ Workspace.State workspaceState = contentType == AppsCustomizePagedView.ContentType.Widgets ?
+ Workspace.State.OVERVIEW_HIDDEN : Workspace.State.NORMAL_HIDDEN;
Animator workspaceAnim =
- mWorkspace.getChangeStateAnimation(Workspace.State.SMALL, animated);
+ mWorkspace.getChangeStateAnimation(workspaceState, animated);
if (!LauncherAppState.isDisableAllApps()
|| contentType == AppsCustomizePagedView.ContentType.Widgets) {
// Set the content type for the all apps/widgets space
@@ -3175,65 +3197,151 @@ public class Launcher extends Activity
}
if (animated) {
- toView.setScaleX(scale);
- toView.setScaleY(scale);
- final LauncherViewPropertyAnimator scaleAnim = new LauncherViewPropertyAnimator(toView);
- scaleAnim.
- scaleX(1f).scaleY(1f).
- setDuration(duration).
- setInterpolator(new Workspace.ZoomOutInterpolator());
+ if (!material) {
+ toView.setScaleX(scale);
+ toView.setScaleY(scale);
+ final LauncherViewPropertyAnimator scaleAnim =
+ new LauncherViewPropertyAnimator(toView);
+ scaleAnim.
+ scaleX(1f).scaleY(1f).
+ setDuration(duration).
+ setInterpolator(new Workspace.ZoomOutInterpolator());
+
+ toView.setVisibility(View.VISIBLE);
+ toView.setAlpha(0f);
+ final ObjectAnimator alphaAnim = LauncherAnimUtils
+ .ofFloat(toView, "alpha", 0f, 1f)
+ .setDuration(fadeDuration);
+ alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
+ alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (animation == null) {
+ throw new RuntimeException("animation is null");
+ }
+ float t = (Float) animation.getAnimatedValue();
+ dispatchOnLauncherTransitionStep(fromView, t);
+ dispatchOnLauncherTransitionStep(toView, t);
+ }
+ });
- toView.setVisibility(View.VISIBLE);
- toView.setAlpha(0f);
- final ObjectAnimator alphaAnim = LauncherAnimUtils
- .ofFloat(toView, "alpha", 0f, 1f)
- .setDuration(fadeDuration);
- alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
- alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- if (animation == null) {
- throw new RuntimeException("animation is null");
+ // toView should appear right at the end of the workspace shrink
+ // animation
+ mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+ mStateAnimation.play(scaleAnim).after(startDelay);
+ mStateAnimation.play(alphaAnim).after(startDelay);
+
+ mStateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Prepare the position
+ toView.setTranslationX(0.0f);
+ toView.setTranslationY(0.0f);
+ toView.setVisibility(View.VISIBLE);
+ toView.bringToFront();
}
- float t = (Float) animation.getAnimatedValue();
- dispatchOnLauncherTransitionStep(fromView, t);
- dispatchOnLauncherTransitionStep(toView, t);
- }
- });
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dispatchOnLauncherTransitionEnd(fromView, animated, false);
+ dispatchOnLauncherTransitionEnd(toView, animated, false);
+
+ // Hide the search bar
+ if (mSearchDropTargetBar != null) {
+ mSearchDropTargetBar.hideSearchBar(false);
+ }
+ }
+ });
+ } else {
+ int width = toView.getMeasuredWidth();
+ int height = toView.getMeasuredHeight();
+ float revealRadius = (float) Math.sqrt((width * width) / 4 + height * height);
- // toView should appear right at the end of the workspace shrink
- // animation
- mStateAnimation = LauncherAnimUtils.createAnimatorSet();
- mStateAnimation.play(scaleAnim).after(startDelay);
- mStateAnimation.play(alphaAnim).after(startDelay);
+ mStateAnimation = LauncherAnimUtils.createAnimatorSet();
- mStateAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- // Prepare the position
- toView.setTranslationX(0.0f);
- toView.setTranslationY(0.0f);
- toView.setVisibility(View.VISIBLE);
- toView.bringToFront();
+ AppsCustomizePagedView content = (AppsCustomizePagedView)
+ toView.findViewById(R.id.apps_customize_pane_content);
+
+ View page = content.getPageAt(content.getCurrentPage());
+ View revealView = content;
+
+ float yDrift = height / 2f - 400;
+
+ LauncherViewPropertyAnimator panelAlphaAndDrift =
+ new LauncherViewPropertyAnimator(revealView);
+ revealView.setTranslationY(yDrift);
+ revealView.setAlpha(0.3f);
+ panelAlphaAndDrift.alpha(1)
+ .translationY(0)
+ .setDuration(revealDuration)
+ .setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ mStateAnimation.play(panelAlphaAndDrift);
+
+ if (page instanceof CellLayout) {
+ CellLayout cellLayout = (CellLayout) page;
+ cellLayout.enableHardwareLayer(true);
+
+ View iconsView = cellLayout.getShortcutsAndWidgets();
+ iconsView.setAlpha(0f);
+
+ LauncherViewPropertyAnimator iconsAlpha =
+ new LauncherViewPropertyAnimator(iconsView);
+ iconsAlpha.alpha(1f)
+ .setDuration(revealDuration - 100)
+ .setInterpolator(new LogDecelerateInterpolator(100, 0));
+ mStateAnimation.play(iconsAlpha);
}
- @Override
- public void onAnimationEnd(Animator animation) {
- dispatchOnLauncherTransitionEnd(fromView, animated, false);
- dispatchOnLauncherTransitionEnd(toView, animated, false);
- // Hide the search bar
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.hideSearchBar(false);
+ View pageIndicators = toView.findViewById(R.id.apps_customize_page_indicator);
+ pageIndicators.setAlpha(0f);
+ final LauncherViewPropertyAnimator indicatorsAlpha =
+ new LauncherViewPropertyAnimator(pageIndicators);
+ indicatorsAlpha.alpha(1f);
+ indicatorsAlpha.setDuration(revealDuration);
+ mStateAnimation.play(indicatorsAlpha);
+
+ width = revealView.getMeasuredWidth();
+
+ Animator reveal =
+ ViewAnimationUtils.createCircularReveal(revealView, width / 2,
+ height / 2 + 100, 0f, revealRadius);
+ reveal.setDuration(revealDuration);
+ reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ toView.setTranslationX(0);
+ toView.setTranslationY(0);
+ toView.setAlpha(1f);
+ // toView should appear right at the end of the workspace shrink
+ // animation
+ mStateAnimation.play(reveal);
+
+ reveal.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Prepare the position
+ toView.bringToFront();
+ toView.setVisibility(View.VISIBLE);
}
- }
- });
+ });
- if (workspaceAnim != null) {
- mStateAnimation.play(workspaceAnim);
+ mStateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dispatchOnLauncherTransitionEnd(fromView, animated, false);
+ dispatchOnLauncherTransitionEnd(toView, animated, false);
+
+ // Hide the search bar
+ if (mSearchDropTargetBar != null) {
+ mSearchDropTargetBar.hideSearchBar(false);
+ }
+ }
+ });
}
boolean delayAnim = false;
-
+ if (workspaceAnim != null) {
+ mStateAnimation.play(workspaceAnim);
+ }
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
dispatchOnLauncherTransitionPrepare(toView, animated, false);
@@ -3305,11 +3413,15 @@ public class Launcher extends Activity
mStateAnimation.cancel();
mStateAnimation = null;
}
+
+ boolean material = Utilities.isLmp();
+
Resources res = getResources();
final int duration = res.getInteger(R.integer.config_appsCustomizeZoomOutTime);
- final int fadeOutDuration =
- res.getInteger(R.integer.config_appsCustomizeFadeOutTime);
+ final int fadeOutDuration = res.getInteger(R.integer.config_appsCustomizeFadeOutTime);
+ final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
+
final float scaleFactor = (float)
res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
final View fromView = mAppsCustomizeTabHost;
@@ -3328,31 +3440,116 @@ public class Launcher extends Activity
setPivotsForZoom(fromView, scaleFactor);
showHotseat(animated);
if (animated) {
- final LauncherViewPropertyAnimator scaleAnim =
- new LauncherViewPropertyAnimator(fromView);
- scaleAnim.
- scaleX(scaleFactor).scaleY(scaleFactor).
- setDuration(duration).
- setInterpolator(new Workspace.ZoomInInterpolator());
-
- final ObjectAnimator alphaAnim = LauncherAnimUtils
- .ofFloat(fromView, "alpha", 1f, 0f)
- .setDuration(fadeOutDuration);
- alphaAnim.setInterpolator(new AccelerateDecelerateInterpolator());
- alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = 1f - (Float) animation.getAnimatedValue();
- dispatchOnLauncherTransitionStep(fromView, t);
- dispatchOnLauncherTransitionStep(toView, t);
+ if (!material) {
+ final LauncherViewPropertyAnimator scaleAnim =
+ new LauncherViewPropertyAnimator(fromView);
+ scaleAnim.
+ scaleX(scaleFactor).scaleY(scaleFactor).
+ setDuration(duration).
+ setInterpolator(new Workspace.ZoomInInterpolator());
+
+ final ObjectAnimator alphaAnim = LauncherAnimUtils
+ .ofFloat(fromView, "alpha", 1f, 0f)
+ .setDuration(fadeOutDuration);
+ alphaAnim.setInterpolator(new AccelerateDecelerateInterpolator());
+ alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = 1f - (Float) animation.getAnimatedValue();
+ dispatchOnLauncherTransitionStep(fromView, t);
+ dispatchOnLauncherTransitionStep(toView, t);
+ }
+ });
+
+ mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+
+ dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+ dispatchOnLauncherTransitionPrepare(toView, animated, true);
+ mAppsCustomizeContent.stopScrolling();
+
+ mStateAnimation.playTogether(scaleAnim, alphaAnim);
+ } else {
+ mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+
+ int width = fromView.getMeasuredWidth();
+ int height = fromView.getMeasuredHeight();
+ float revealRadius = (float) Math.sqrt((width * width) / 4 + height * height);
+
+ AppsCustomizePagedView content = (AppsCustomizePagedView)
+ fromView.findViewById(R.id.apps_customize_pane_content);
+
+ final View page = content.getPageAt(content.getNextPage());
+ View revealView = page;
+
+ float yDrift = height / 2f - 400;
+
+ LauncherViewPropertyAnimator panelAlphaAndDrift =
+ new LauncherViewPropertyAnimator(revealView);
+ revealView.setTranslationY(0);
+ revealView.setAlpha(1);
+ panelAlphaAndDrift.alpha(0)
+ .translationY(yDrift)
+ .setDuration(revealDuration)
+ .setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ mStateAnimation.play(panelAlphaAndDrift);
+
+ if (page instanceof CellLayout) {
+ final CellLayout cellLayout = (CellLayout) page;
+ cellLayout.enableHardwareLayer(true);
+
+ final View iconsView = cellLayout.getShortcutsAndWidgets();
+
+ LauncherViewPropertyAnimator iconsAlpha =
+ new LauncherViewPropertyAnimator(iconsView);
+ iconsAlpha.alpha(0f)
+ .setDuration(revealDuration - 100)
+ .setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ mStateAnimation.play(iconsAlpha);
+
+ mStateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellLayout.setTranslationY(0);
+ cellLayout.setAlpha(1f);
+ iconsView.setAlpha(1f);
+ }
+ });
}
- });
- mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+ View pageIndicators = fromView.findViewById(R.id.apps_customize_page_indicator);
+ final LauncherViewPropertyAnimator indicatorsAlpha =
+ new LauncherViewPropertyAnimator(pageIndicators);
+ indicatorsAlpha.alpha(0f);
+ indicatorsAlpha.setDuration(revealDuration);
+ indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
+ mStateAnimation.play(indicatorsAlpha);
- dispatchOnLauncherTransitionPrepare(fromView, animated, true);
- dispatchOnLauncherTransitionPrepare(toView, animated, true);
- mAppsCustomizeContent.stopScrolling();
+ width = revealView.getMeasuredWidth();
+
+ Animator reveal =
+ ViewAnimationUtils.createCircularReveal(revealView, width / 2,
+ height / 2 + 100, revealRadius, 0f);
+ reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+ reveal.setDuration(revealDuration);
+
+ reveal.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ fromView.setVisibility(View.GONE);
+ }
+ });
+
+ dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+ dispatchOnLauncherTransitionPrepare(toView, animated, true);
+ mAppsCustomizeContent.stopScrolling();
+
+ mStateAnimation.play(reveal);
+ }
+ if (workspaceAnim != null) {
+ mStateAnimation.play(workspaceAnim);
+ }
mStateAnimation.addListener(new AnimatorListenerAdapter() {
@Override
@@ -3367,10 +3564,6 @@ public class Launcher extends Activity
}
});
- mStateAnimation.playTogether(scaleAnim, alphaAnim);
- if (workspaceAnim != null) {
- mStateAnimation.play(workspaceAnim);
- }
dispatchOnLauncherTransitionStart(fromView, animated, true);
dispatchOnLauncherTransitionStart(toView, animated, true);
LauncherAnimUtils.startAnimationAfterNextDraw(mStateAnimation, toView);
@@ -3835,7 +4028,7 @@ public class Launcher extends Activity
text.clear();
// Populate event with a fake title based on the current state.
if (mState == State.APPS_CUSTOMIZE) {
- text.add(mAppsCustomizeTabHost.getCurrentTabView().getContentDescription());
+ text.add(mAppsCustomizeTabHost.getContentTag());
} else {
text.add(getString(R.string.all_apps_home_button_label));
}
@@ -4197,13 +4390,20 @@ public class Launcher extends Activity
}
final Workspace workspace = mWorkspace;
- final int appWidgetId = item.appWidgetId;
- final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
- if (DEBUG_WIDGETS) {
- Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider);
- }
+ final AppWidgetProviderInfo appWidgetInfo;
+ if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ final int appWidgetId = item.appWidgetId;
+ appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ if (DEBUG_WIDGETS) {
+ Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider);
+ }
- item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+ item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+ } else {
+ appWidgetInfo = null;
+ item.hostView = new LauncherAppWidgetHostView(this, false);
+ item.hostView.updateAppWidget(null);
+ }
item.hostView.setTag(item);
item.onBindAppWidget(this);
@@ -4363,7 +4563,7 @@ public class Launcher extends Activity
}
if (mWorkspace != null) {
- mWorkspace.updateShortcuts(apps);
+ mWorkspace.updateShortcutsAndWidgets(apps);
}
if (!LauncherAppState.isDisableAllApps() &&
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index f47fd13ec..7eb005255 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -18,6 +18,7 @@ package com.android.launcher3;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
+import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -39,12 +40,28 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
private float mSlop;
+ private boolean mWidgetReady;
+
public LauncherAppWidgetHostView(Context context) {
+ this(context, true);
+ }
+
+ public LauncherAppWidgetHostView(Context context, boolean widgetReady) {
super(context);
mContext = context;
mLongPressHelper = new CheckLongPressHelper(this);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mDragLayer = ((Launcher) context).getDragLayer();
+ mWidgetReady = widgetReady;
+ }
+
+ @Override
+ public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
+ int maxHeight) {
+ // If the widget is not yet ready, the app widget size cannot be updated.
+ if (mWidgetReady) {
+ super.updateAppWidgetSize(newOptions, minWidth, minHeight, maxWidth, maxHeight);
+ }
}
@Override
@@ -53,6 +70,15 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
}
@Override
+ protected View getDefaultView() {
+ if (mWidgetReady) {
+ return super.getDefaultView();
+ } else {
+ return mInflater.inflate(R.layout.appwidget_not_ready, this, false);
+ }
+ }
+
+ @Override
public void updateAppWidget(RemoteViews remoteViews) {
// Store the orientation in which the widget was inflated
mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index bec1f9eb3..b3ac12b37 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -28,6 +28,18 @@ import com.android.launcher3.compat.UserHandleCompat;
*/
public class LauncherAppWidgetInfo extends ItemInfo {
+ public static final int RESTORE_COMPLETED = 0;
+
+ /**
+ * This is set during the package backup creation.
+ */
+ public static final int RESTORE_REMAP_PENDING = 1;
+
+ /**
+ * Widget provider is not yet installed.
+ */
+ public static final int RESTORE_PROVIDER_PENDING = 2;
+
/**
* Indicates that the widget hasn't been instantiated yet.
*/
@@ -45,6 +57,11 @@ public class LauncherAppWidgetInfo extends ItemInfo {
int minWidth = -1;
int minHeight = -1;
+ /**
+ * Indicates the restore status of the widget.
+ */
+ int restoreStatus;
+
private boolean mHasNotifiedInitialWidgetSizeChanged;
/**
@@ -64,6 +81,7 @@ public class LauncherAppWidgetInfo extends ItemInfo {
spanY = -1;
// We only support app widgets on current user.
user = UserHandleCompat.myUserHandle();
+ restoreStatus = RESTORE_COMPLETED;
}
@Override
@@ -101,4 +119,8 @@ public class LauncherAppWidgetInfo extends ItemInfo {
super.unbind();
hostView = null;
}
+
+ public final boolean isWidgetIdValid() {
+ return restoreStatus != RESTORE_REMAP_PENDING;
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index b01db7194..673fef981 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2047,6 +2047,8 @@ public class LauncherModel extends BroadcastReceiver
info.spanX = 1;
info.spanY = 1;
info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+ info.isDisabled = isSafeMode
+ && !Utilities.isSystemApp(context, intent);
// check & update map of what's occupied
deleteOnInvalidPlacement.set(false);
@@ -2123,31 +2125,54 @@ public class LauncherModel extends BroadcastReceiver
// Read all Launcher-specific widget details
int appWidgetId = c.getInt(appWidgetIdIndex);
String savedProvider = c.getString(appWidgetProviderIndex);
-
id = c.getLong(idIndex);
- final AppWidgetProviderInfo provider =
- widgets.getAppWidgetInfo(appWidgetId);
-
- if (!isSafeMode && (provider == null || provider.provider == null ||
- provider.provider.getPackageName() == null)) {
- String log = "Deleting widget that isn't installed anymore: id="
- + id + " appWidgetId=" + appWidgetId;
+ final int restoreStatus = c.getInt(restoredIndex);
+ final boolean restorePending = Utilities.isLmp()
+ && (restoreStatus ==
+ LauncherAppWidgetInfo.RESTORE_REMAP_PENDING);
+ final boolean providerPending = Utilities.isLmp()
+ && (restoreStatus ==
+ LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING);
+
+ // Do not try to get the provider if restore is pending, as the
+ // widget id is invalid, and it might point to some other provider.
+ final AppWidgetProviderInfo provider = restorePending ? null
+ : widgets.getAppWidgetInfo(appWidgetId);
+ boolean providerValid = isValidProvider(provider);
+
+ // Skip provider check,
+ // 1. when the widget id re-map is pending
+ // 2. provider is pending install for a restored widget
+ if (!isSafeMode && !providerPending && !restorePending
+ && !providerValid) {
+ String log = "Deleting widget that isn't installed anymore: "
+ + "id=" + id + " appWidgetId=" + appWidgetId;
Log.e(TAG, log);
Launcher.addDumpLog(TAG, log, false);
itemsToRemove.add(id);
} else {
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- provider.provider);
+ if (providerValid) {
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ provider.provider);
+ int[] minSpan =
+ Launcher.getMinSpanForWidget(context, provider);
+ appWidgetInfo.minSpanX = minSpan[0];
+ appWidgetInfo.minSpanY = minSpan[1];
+ } else {
+ Log.v(TAG, "Widget restore pending id=" + id
+ + " appWidgetId=" + appWidgetId
+ + " status =" + restoreStatus);
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ ComponentName.unflattenFromString(savedProvider));
+ appWidgetInfo.restoreStatus = restoreStatus;
+ }
appWidgetInfo.id = id;
appWidgetInfo.screenId = c.getInt(screenIndex);
appWidgetInfo.cellX = c.getInt(cellXIndex);
appWidgetInfo.cellY = c.getInt(cellYIndex);
appWidgetInfo.spanX = c.getInt(spanXIndex);
appWidgetInfo.spanY = c.getInt(spanYIndex);
- int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
- appWidgetInfo.minSpanX = minSpan[0];
- appWidgetInfo.minSpanY = minSpan[1];
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
@@ -2167,14 +2192,20 @@ public class LauncherModel extends BroadcastReceiver
}
break;
}
- String providerName = provider.provider.flattenToString();
- if (!providerName.equals(savedProvider)) {
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
- providerName);
- String where = BaseColumns._ID + "= ?";
- String[] args = {Integer.toString(c.getInt(idIndex))};
- contentResolver.update(contentUri, values, where, args);
+
+ if (providerValid) {
+ String providerName = provider.provider.flattenToString();
+
+ if (!providerName.equals(savedProvider) || providerPending) {
+ ContentValues values = new ContentValues();
+ values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
+ providerName);
+ values.put(LauncherSettings.Favorites.RESTORED,
+ LauncherAppWidgetInfo.RESTORE_COMPLETED);
+ String where = BaseColumns._ID + "= ?";
+ String[] args = {Long.toString(id)};
+ contentResolver.update(contentUri, values, where, args);
+ }
}
sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
sBgAppWidgets.add(appWidgetInfo);
@@ -3552,18 +3583,18 @@ public class LauncherModel extends BroadcastReceiver
mCollator = Collator.getInstance();
}
public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {
- CharSequence labelA, labelB;
+ String labelA, labelB;
ComponentName keyA = a.getComponentName();
ComponentName keyB = b.getComponentName();
if (mLabelCache.containsKey(keyA)) {
- labelA = mLabelCache.get(keyA);
+ labelA = mLabelCache.get(keyA).toString();
} else {
labelA = a.getLabel().toString().trim();
mLabelCache.put(keyA, labelA);
}
if (mLabelCache.containsKey(keyB)) {
- labelB = mLabelCache.get(keyB);
+ labelB = mLabelCache.get(keyB).toString();
} else {
labelB = b.getLabel().toString().trim();
@@ -3603,6 +3634,11 @@ public class LauncherModel extends BroadcastReceiver
}
};
+ static boolean isValidProvider(AppWidgetProviderInfo provider) {
+ return (provider != null) && (provider.provider != null)
+ && (provider.provider.getPackageName() != null);
+ }
+
public void dumpState() {
Log.d(TAG, "mCallbacks=" + mCallbacks);
AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 2256179c3..3ff617631 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -99,6 +99,8 @@ public class LauncherProvider extends ContentProvider {
private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
"com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
+ private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd";
+
private LauncherProviderChangeListener mListener;
/**
@@ -175,6 +177,14 @@ public class LauncherProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues initialValues) {
SqlArguments args = new SqlArguments(uri);
+ // In very limited cases, we support system|signature permission apps to add to the db
+ String externalAdd = uri.getQueryParameter(URI_PARAM_IS_EXTERNAL_ADD);
+ if (externalAdd != null && "true".equals(externalAdd)) {
+ if (!mOpenHelper.initializeExternalAdd(initialValues)) {
+ return null;
+ }
+ }
+
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
addModifiedTime(initialValues);
final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
@@ -186,6 +196,7 @@ public class LauncherProvider extends ContentProvider {
return uri;
}
+
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
SqlArguments args = new SqlArguments(uri);
@@ -1245,6 +1256,37 @@ public class LauncherProvider extends ContentProvider {
if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId);
}
+ private boolean initializeExternalAdd(ContentValues values) {
+ // 1. Ensure that externally added items have a valid item id
+ long id = generateNewItemId();
+ values.put(LauncherSettings.Favorites._ID, id);
+
+ // 2. In the case of an app widget, and if no app widget id is specified, we
+ // attempt allocate and bind the widget.
+ Integer itemType = values.getAsInteger(LauncherSettings.Favorites.ITEM_TYPE);
+ if (itemType != null &&
+ itemType.intValue() == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
+ !values.containsKey(LauncherSettings.Favorites.APPWIDGET_ID)) {
+
+ final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
+ ComponentName cn = ComponentName.unflattenFromString(
+ values.getAsString(Favorites.APPWIDGET_PROVIDER));
+
+ if (cn != null) {
+ try {
+ int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+ if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
+ return false;
+ }
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to initialize external widget", e);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
private static final void beginDocument(XmlPullParser parser, String firstElementName)
throws XmlPullParserException, IOException {
int type;
@@ -1752,6 +1794,7 @@ public class LauncherProvider extends ContentProvider {
return false;
}
+
private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn,
Bundle extras) {
boolean allocatedAppWidgets = false;
diff --git a/src/com/android/launcher3/LogAccelerateInterpolator.java b/src/com/android/launcher3/LogAccelerateInterpolator.java
new file mode 100644
index 000000000..c3bbfa536
--- /dev/null
+++ b/src/com/android/launcher3/LogAccelerateInterpolator.java
@@ -0,0 +1,25 @@
+package com.android.launcher3;
+
+import android.animation.TimeInterpolator;
+
+public class LogAccelerateInterpolator implements TimeInterpolator {
+
+ int mBase;
+ int mDrift;
+ final float mLogScale;
+
+ public LogAccelerateInterpolator(int base, int drift) {
+ mBase = base;
+ mDrift = drift;
+ mLogScale = 1f / computeLog(1, mBase, mDrift);
+ }
+
+ static float computeLog(float t, int base, int drift) {
+ return (float) -Math.pow(base, -t) + 1 + (drift * t);
+ }
+
+ @Override
+ public float getInterpolation(float t) {
+ return 1 - computeLog(1 - t, mBase, mDrift) * mLogScale;
+ }
+}
diff --git a/src/com/android/launcher3/LogDecelerateInterpolator.java b/src/com/android/launcher3/LogDecelerateInterpolator.java
new file mode 100644
index 000000000..4c5f6f08c
--- /dev/null
+++ b/src/com/android/launcher3/LogDecelerateInterpolator.java
@@ -0,0 +1,26 @@
+package com.android.launcher3;
+
+import android.animation.TimeInterpolator;
+
+public class LogDecelerateInterpolator implements TimeInterpolator {
+
+ int mBase;
+ int mDrift;
+ final float mLogScale;
+
+ public LogDecelerateInterpolator(int base, int drift) {
+ mBase = base;
+ mDrift = drift;
+
+ mLogScale = 1f / computeLog(1, mBase, mDrift);
+ }
+
+ static float computeLog(float t, int base, int drift) {
+ return (float) -Math.pow(base, -t) + 1 + (drift * t);
+ }
+
+ @Override
+ public float getInterpolation(float t) {
+ return computeLog(t, mBase, mDrift) * mLogScale;
+ }
+}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 7e1f0d649..266e9e07f 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -79,6 +79,12 @@ public class ShortcutInfo extends ItemInfo {
private Bitmap mIcon;
/**
+ * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
+ * sd-card is not available).
+ */
+ boolean isDisabled = false;
+
+ /**
* The installation state of the package that this shortcut represents.
*/
protected int mState;
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index 882fb04a3..f3977e456 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -32,7 +32,6 @@ public class Stats {
private static final boolean LOCAL_LAUNCH_LOG = true;
public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
- public static final String PERM_LAUNCH = "com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS";
public static final String EXTRA_INTENT = "intent";
public static final String EXTRA_CONTAINER = "container";
public static final String EXTRA_SCREEN = "screen";
@@ -53,6 +52,8 @@ public class Stats {
private final Launcher mLauncher;
+ private final String mLaunchBroadcastPermission;
+
DataOutputStream mLog;
ArrayList<String> mIntents;
@@ -61,6 +62,9 @@ public class Stats {
public Stats(Launcher launcher) {
mLauncher = launcher;
+ mLaunchBroadcastPermission =
+ launcher.getResources().getString(R.string.receive_launch_broadcasts_permission);
+
loadStats();
if (LOCAL_LAUNCH_LOG) {
@@ -87,7 +91,7 @@ public class Stats {
}
},
new IntentFilter(ACTION_LAUNCH),
- PERM_LAUNCH,
+ mLaunchBroadcastPermission,
null
);
}
@@ -120,7 +124,7 @@ public class Stats {
.putExtra(EXTRA_CELLX, shortcut.cellX)
.putExtra(EXTRA_CELLY, shortcut.cellY);
}
- mLauncher.sendBroadcast(broadcastIntent, PERM_LAUNCH);
+ mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
incrementLaunch(flat);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 74b6e47f1..0a711c5dd 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,14 +18,17 @@ package com.android.launcher3;
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
@@ -52,10 +55,6 @@ public final class Utilities {
public static int sIconTextureWidth = -1;
public static int sIconTextureHeight = -1;
- private static final Paint sBlurPaint = new Paint();
- private static final Paint sGlowColorPressedPaint = new Paint();
- private static final Paint sGlowColorFocusedPaint = new Paint();
- private static final Paint sDisabledPaint = new Paint();
private static final Rect sOldBounds = new Rect();
private static final Canvas sCanvas = new Canvas();
@@ -75,7 +74,7 @@ public final class Utilities {
/**
* Returns a FastBitmapDrawable with the icon, accurately sized.
*/
- static Drawable createIconDrawable(Bitmap icon) {
+ static FastBitmapDrawable createIconDrawable(Bitmap icon) {
FastBitmapDrawable d = new FastBitmapDrawable(icon);
d.setFilterBitmap(true);
resizeIconDrawable(d);
@@ -332,15 +331,6 @@ public final class Utilities {
sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
sIconTextureWidth = sIconTextureHeight = sIconWidth;
-
- sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
- sGlowColorPressedPaint.setColor(0xffffc300);
- sGlowColorFocusedPaint.setColor(0xffff8e00);
-
- ColorMatrix cm = new ColorMatrix();
- cm.setSaturation(0.2f);
- sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
- sDisabledPaint.setAlpha(0x88);
}
public static void setIconSize(int widthPx) {
@@ -378,4 +368,29 @@ public final class Utilities {
"or use the exported attribute for this activity.", e);
}
}
+
+ static boolean isSystemApp(Context context, Intent intent) {
+ PackageManager pm = context.getPackageManager();
+ ComponentName cn = intent.getComponent();
+ String packageName = null;
+ if (cn == null) {
+ ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if ((info != null) && (info.activityInfo != null)) {
+ packageName = info.activityInfo.packageName;
+ }
+ } else {
+ packageName = cn.getPackageName();
+ }
+ if (packageName != null) {
+ try {
+ PackageInfo info = pm.getPackageInfo(packageName, 0);
+ return (info != null) && (info.applicationInfo != null) &&
+ ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a8e7580c3..1011588c8 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -30,6 +30,8 @@ import android.app.WallpaperManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -47,6 +49,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.Parcelable;
+import android.provider.BaseColumns;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
@@ -61,15 +64,16 @@ import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
-import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.compat.UserHandleCompat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Set;
/**
* The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -109,9 +113,6 @@ public class Workspace extends SmoothPagedView
// These properties refer to the background protection gradient used for AllApps and Customize
private ValueAnimator mBackgroundFadeInAnimation;
private ValueAnimator mBackgroundFadeOutAnimation;
- private Drawable mBackground;
- boolean mDrawBackground = true;
- private float mBackgroundAlpha = 0;
private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
private long mTouchDownTime = -1;
@@ -191,7 +192,7 @@ public class Workspace extends SmoothPagedView
// State variable that indicates whether the pages are small (ie when you're
// in all apps or customize mode)
- enum State { NORMAL, SPRING_LOADED, SMALL, OVERVIEW};
+ enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN};
private State mState = State.NORMAL;
private boolean mIsSwitchingState = false;
@@ -445,13 +446,6 @@ public class Workspace extends SmoothPagedView
setMinScale(mOverviewModeShrinkFactor);
setupLayoutTransition();
- final Resources res = getResources();
- try {
- mBackground = res.getDrawable(R.drawable.apps_customize_bg);
- } catch (Resources.NotFoundException e) {
- // In this case, we will skip drawing background protection
- }
-
mWallpaperOffset = new WallpaperOffsetInterpolator();
Display display = mLauncher.getWindowManager().getDefaultDisplay();
display.getSize(mDisplaySize);
@@ -1068,8 +1062,8 @@ public class Workspace extends SmoothPagedView
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
- return (isSmall() || !isFinishedSwitchingState())
- || (!isSmall() && indexOfChild(v) != mCurrentPage);
+ return (workspaceInModalState() || !isFinishedSwitchingState())
+ || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);
}
public boolean isSwitchingState() {
@@ -1088,7 +1082,7 @@ public class Workspace extends SmoothPagedView
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
- if (isSmall() || !isFinishedSwitchingState()) {
+ if (workspaceInModalState() || !isFinishedSwitchingState()) {
// when the home screens are shrunken, shouldn't allow side-scrolling
return false;
}
@@ -1226,7 +1220,7 @@ public class Workspace extends SmoothPagedView
}
if (mDragController.isDragging()) {
- if (isSmall()) {
+ if (workspaceInModalState()) {
// If we are in springloaded mode, then force an event to check if the current touch
// is under a new page (to scroll to)
mDragController.forceTouchMove();
@@ -1500,7 +1494,7 @@ public class Workspace extends SmoothPagedView
}
void showOutlines() {
- if (!isSmall() && !mIsSwitchingState) {
+ if (!workspaceInModalState() && !mIsSwitchingState) {
if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
@@ -1510,7 +1504,7 @@ public class Workspace extends SmoothPagedView
}
void hideOutlines() {
- if (!isSmall() && !mIsSwitchingState) {
+ if (!workspaceInModalState() && !mIsSwitchingState) {
if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
@@ -1538,15 +1532,9 @@ public class Workspace extends SmoothPagedView
return mChildrenOutlineAlpha;
}
- void disableBackground() {
- mDrawBackground = false;
- }
- void enableBackground() {
- mDrawBackground = true;
- }
-
private void animateBackgroundGradient(float finalAlpha, boolean animated) {
- if (mBackground == null) return;
+ final DragLayer dragLayer = mLauncher.getDragLayer();
+
if (mBackgroundFadeInAnimation != null) {
mBackgroundFadeInAnimation.cancel();
mBackgroundFadeInAnimation = null;
@@ -1555,36 +1543,26 @@ public class Workspace extends SmoothPagedView
mBackgroundFadeOutAnimation.cancel();
mBackgroundFadeOutAnimation = null;
}
- float startAlpha = getBackgroundAlpha();
+ float startAlpha = dragLayer.getBackgroundAlpha();
if (finalAlpha != startAlpha) {
if (animated) {
mBackgroundFadeOutAnimation =
LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);
mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
- setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
+ dragLayer.setBackgroundAlpha(
+ ((Float)animation.getAnimatedValue()).floatValue());
}
});
mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
mBackgroundFadeOutAnimation.start();
} else {
- setBackgroundAlpha(finalAlpha);
+ dragLayer.setBackgroundAlpha(finalAlpha);
}
}
}
- public void setBackgroundAlpha(float alpha) {
- if (alpha != mBackgroundAlpha) {
- mBackgroundAlpha = alpha;
- invalidate();
- }
- }
-
- public float getBackgroundAlpha() {
- return mBackgroundAlpha;
- }
-
float backgroundAlphaInterpolator(float r) {
float pivotA = 0.1f;
float pivotB = 0.4f;
@@ -1656,13 +1634,13 @@ public class Workspace extends SmoothPagedView
if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return;
CellLayout cc = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);
- if (progress > 0 && cc.getVisibility() != VISIBLE && !isSmall()) {
+ if (progress > 0 && cc.getVisibility() != VISIBLE && !workspaceInModalState()) {
cc.setVisibility(VISIBLE);
}
mLastCustomContentScrollProgress = progress;
- setBackgroundAlpha(progress * 0.8f);
+ mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
if (mLauncher.getHotseat() != null) {
mLauncher.getHotseat().setTranslationX(translationX);
@@ -1792,25 +1770,12 @@ public class Workspace extends SmoothPagedView
@Override
protected void onDraw(Canvas canvas) {
- // Draw the background gradient if necessary
- if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
- int alpha = (int) (mBackgroundAlpha * 255);
- mBackground.setAlpha(alpha);
- mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(),
- getMeasuredHeight());
- mBackground.draw(canvas);
- }
-
super.onDraw(canvas);
// Call back to LauncherModel to finish binding after the first draw
post(mBindPages);
}
- boolean isDrawingBackgroundGradient() {
- return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);
- }
-
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
if (!mLauncher.isAllAppsVisible()) {
@@ -1826,7 +1791,7 @@ public class Workspace extends SmoothPagedView
@Override
public int getDescendantFocusability() {
- if (isSmall()) {
+ if (workspaceInModalState()) {
return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
}
return super.getDescendantFocusability();
@@ -1844,8 +1809,8 @@ public class Workspace extends SmoothPagedView
}
}
- public boolean isSmall() {
- return mState == State.SMALL || mState == State.SPRING_LOADED || mState == State.OVERVIEW;
+ public boolean workspaceInModalState() {
+ return mState != State.NORMAL;
}
void enableChildrenCache(int fromPage, int toPage) {
@@ -1880,7 +1845,7 @@ public class Workspace extends SmoothPagedView
}
private void updateChildrenLayersEnabled(boolean force) {
- boolean small = mState == State.SMALL || mState == State.OVERVIEW || mIsSwitchingState;
+ boolean small = mState == State.OVERVIEW || mIsSwitchingState;
boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
if (enableChildrenLayers != mChildrenLayersEnabled) {
@@ -2223,6 +2188,8 @@ public class Workspace extends SmoothPagedView
setImportantForAccessibility(accessible);
}
+ private static final int HIDE_WORKSPACE_DURATION = 100;
+
Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {
if (mState == state) {
return null;
@@ -2236,21 +2203,25 @@ public class Workspace extends SmoothPagedView
final State oldState = mState;
final boolean oldStateIsNormal = (oldState == State.NORMAL);
final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
- final boolean oldStateIsSmall = (oldState == State.SMALL);
+ final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN);
+ final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN);
final boolean oldStateIsOverview = (oldState == State.OVERVIEW);
setState(state);
final boolean stateIsNormal = (state == State.NORMAL);
final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
- final boolean stateIsSmall = (state == State.SMALL);
+ final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN);
+ final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN);
final boolean stateIsOverview = (state == State.OVERVIEW);
float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
- float finalHotseatAndPageIndicatorAlpha = (stateIsOverview || stateIsSmall) ? 0f : 1f;
+ float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;
float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;
- float finalWorkspaceTranslationY = stateIsOverview ? getOverviewModeTranslationY() : 0;
+ float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?
+ getOverviewModeTranslationY() : 0;
- boolean workspaceToAllApps = (oldStateIsNormal && stateIsSmall);
- boolean allAppsToWorkspace = (oldStateIsSmall && stateIsNormal);
+ boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);
+ boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);
+ boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);
boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);
boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);
@@ -2265,10 +2236,8 @@ public class Workspace extends SmoothPagedView
if (state != State.NORMAL) {
if (stateIsSpringLoaded) {
mNewScale = mSpringLoadedShrinkFactor;
- } else if (stateIsOverview) {
+ } else if (stateIsOverview || stateIsOverviewHidden) {
mNewScale = mOverviewModeShrinkFactor;
- } else if (stateIsSmall){
- mNewScale = mOverviewModeShrinkFactor - 0.3f;
}
if (workspaceToAllApps) {
updateChildrenLayersEnabled(false);
@@ -2276,8 +2245,8 @@ public class Workspace extends SmoothPagedView
}
final int duration;
- if (workspaceToAllApps) {
- duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime);
+ if (workspaceToAllApps || overviewToAllApps) {
+ duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUnshrinkTime);
} else if (workspaceToOverview || overviewToWorkspace) {
duration = getResources().getInteger(R.integer.config_overviewTransitionTime);
} else {
@@ -2294,7 +2263,7 @@ public class Workspace extends SmoothPagedView
boolean isCurrentPage = (i == snapPage);
float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();
float finalAlpha;
- if (stateIsSmall) {
+ if (stateIsNormalHidden || stateIsOverviewHidden) {
finalAlpha = 0f;
} else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f;
@@ -2331,11 +2300,11 @@ public class Workspace extends SmoothPagedView
final View hotseat = mLauncher.getHotseat();
final View pageIndicator = getPageIndicator();
if (animated) {
- anim.setDuration(duration);
LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);
scale.scaleX(mNewScale)
.scaleY(mNewScale)
.translationY(finalWorkspaceTranslationY)
+ .setDuration(duration)
.setInterpolator(mZoomInInterpolator);
anim.play(scale);
for (int index = 0; index < getChildCount(); index++) {
@@ -2350,6 +2319,7 @@ public class Workspace extends SmoothPagedView
LauncherViewPropertyAnimator alphaAnim =
new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
alphaAnim.alpha(mNewAlphas[i])
+ .setDuration(duration)
.setInterpolator(mZoomInInterpolator);
anim.play(alphaAnim);
}
@@ -2358,6 +2328,7 @@ public class Workspace extends SmoothPagedView
ValueAnimator bgAnim =
LauncherAnimUtils.ofFloat(cl, 0f, 1f);
bgAnim.setInterpolator(mZoomInInterpolator);
+ bgAnim.setDuration(duration);
bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
public void onAnimationUpdate(float a, float b) {
cl.setBackgroundAlpha(
@@ -2400,7 +2371,11 @@ public class Workspace extends SmoothPagedView
hotseatAlpha.setInterpolator(null);
overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
}
- searchBarAlpha.setInterpolator(null);
+
+ overviewPanelAlpha.setDuration(duration);
+ pageIndicatorAlpha.setDuration(duration);
+ hotseatAlpha.setDuration(duration);
+ searchBarAlpha.setDuration(duration);
anim.play(overviewPanelAlpha);
anim.play(hotseatAlpha);
@@ -2425,18 +2400,11 @@ public class Workspace extends SmoothPagedView
}
mLauncher.updateVoiceButtonProxyVisible(false);
- if (stateIsSpringLoaded) {
- // Right now we're covered by Apps Customize
- // Show the background gradient immediately, so the gradient will
- // be showing once AppsCustomize disappears
- animateBackgroundGradient(getResources().getInteger(
- R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);
- } else if (stateIsOverview) {
- animateBackgroundGradient(getResources().getInteger(
- R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, true);
- } else {
- // Fade the background gradient away
+ if (stateIsNormal) {
animateBackgroundGradient(0f, animated);
+ } else {
+ animateBackgroundGradient(getResources().getInteger(
+ R.integer.config_workspaceScrimAlpha) / 100f, animated);
}
return anim;
}
@@ -2822,7 +2790,8 @@ public class Workspace extends SmoothPagedView
}
public boolean transitionStateShouldAllowDrop() {
- return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);
+ return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
+ (mState == State.NORMAL || mState == State.SPRING_LOADED));
}
/**
@@ -3137,7 +3106,12 @@ public class Workspace extends SmoothPagedView
final ItemInfo info = (ItemInfo) cell.getTag();
if (hasMovedLayouts) {
// Reparent the view
- getParentCellLayoutForView(cell).removeView(cell);
+ CellLayout parentCell = getParentCellLayoutForView(cell);
+ if (parentCell != null) {
+ parentCell.removeView(cell);
+ } else if (LauncherAppState.isDogfoodBuild()) {
+ throw new NullPointerException("mDragInfo.cell has null parent");
+ }
addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],
info.spanX, info.spanY);
}
@@ -3591,11 +3565,17 @@ public class Workspace extends SmoothPagedView
public void onDragOver(DragObject d) {
// Skip drag over events while we are dragging over side pages
- if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;
+ if (mInScrollArea || !transitionStateShouldAllowDrop()) return;
Rect r = new Rect();
CellLayout layout = null;
ItemInfo item = (ItemInfo) d.dragInfo;
+ if (item == null) {
+ if (LauncherAppState.isDogfoodBuild()) {
+ throw new NullPointerException("DragObject has null info");
+ }
+ return;
+ }
// Ensure that we have proper spans for the item that we are dropping
if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
@@ -3604,7 +3584,7 @@ public class Workspace extends SmoothPagedView
final View child = (mDragInfo == null) ? null : mDragInfo.cell;
// Identify whether we have dragged over a side page
- if (isSmall()) {
+ if (workspaceInModalState()) {
if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {
if (isPointInSelfOverHotseat(d.x, d.y, r)) {
layout = mLauncher.getHotseat().getLayout();
@@ -4223,6 +4203,8 @@ public class Workspace extends SmoothPagedView
CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);
if (parentCell != null) {
parentCell.removeView(mDragInfo.cell);
+ } else if (LauncherAppState.isDogfoodBuild()) {
+ throw new NullPointerException("mDragInfo.cell has null parent");
}
if (mDragInfo.cell instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
@@ -4482,7 +4464,7 @@ public class Workspace extends SmoothPagedView
@Override
public void scrollLeft() {
- if (!isSmall() && !mIsSwitchingState) {
+ if (!workspaceInModalState() && !mIsSwitchingState) {
super.scrollLeft();
}
Folder openFolder = getOpenFolder();
@@ -4493,7 +4475,7 @@ public class Workspace extends SmoothPagedView
@Override
public void scrollRight() {
- if (!isSmall() && !mIsSwitchingState) {
+ if (!workspaceInModalState() && !mIsSwitchingState) {
super.scrollRight();
}
Folder openFolder = getOpenFolder();
@@ -4515,7 +4497,7 @@ public class Workspace extends SmoothPagedView
}
boolean result = false;
- if (!isSmall() && !mIsSwitchingState && getOpenFolder() == null) {
+ if (!workspaceInModalState() && !mIsSwitchingState && getOpenFolder() == null) {
mInScrollArea = true;
final int page = getNextPage() +
@@ -4609,7 +4591,7 @@ public class Workspace extends SmoothPagedView
public Folder getFolderForTag(final Object tag) {
final Folder[] value = new Folder[1];
- mapOverShortcuts(MAP_NO_RECURSE, new ShortcutOperator() {
+ mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v instanceof Folder) {
@@ -4627,7 +4609,7 @@ public class Workspace extends SmoothPagedView
public View getViewForTag(final Object tag) {
final View[] value = new View[1];
- mapOverShortcuts(MAP_NO_RECURSE, new ShortcutOperator() {
+ mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v.getTag() == tag) {
@@ -4641,7 +4623,7 @@ public class Workspace extends SmoothPagedView
}
void clearDropTargets() {
- mapOverShortcuts(MAP_NO_RECURSE, new ShortcutOperator() {
+ mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v instanceof DropTarget) {
@@ -4790,14 +4772,14 @@ public class Workspace extends SmoothPagedView
shortcutInfo.updateIcon(mIconCache);
shortcutInfo.title = appInfo.title.toString();
shortcutInfo.contentDescription = appInfo.contentDescription;
- shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);
+ shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true);
}
}
}
- interface ShortcutOperator {
+ interface ItemOperator {
/**
- * Process the next shortcut, possibly with side-effect on {@link ShortcutOperator#value}.
+ * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.
*
* @param info info for the shortcut
* @param view view for the shortcut
@@ -4808,12 +4790,12 @@ public class Workspace extends SmoothPagedView
}
/**
- * Map the operator over the shortcuts, return the first-non-null value.
+ * Map the operator over the shortcuts and widgets, return the first-non-null value.
*
* @param recurse true: iterate over folder children. false: op get the folders themselves.
* @param op the operator to map over the shortcuts
*/
- void mapOverShortcuts(boolean recurse, ShortcutOperator op) {
+ void mapOverItems(boolean recurse, ItemOperator op) {
ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();
final int containerCount = containers.size();
for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {
@@ -4844,14 +4826,16 @@ public class Workspace extends SmoothPagedView
}
}
- void updateShortcuts(ArrayList<AppInfo> apps) {
+ void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {
// Create a map of the apps to test against
final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();
+ final HashSet<String> pkgNames = new HashSet<>();
for (AppInfo ai : apps) {
appsMap.put(ai.componentName, ai);
+ pkgNames.add(ai.componentName.getPackageName());
}
- mapOverShortcuts(MAP_RECURSE, new ShortcutOperator() {
+ mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (info instanceof ShortcutInfo) {
@@ -4864,6 +4848,8 @@ public class Workspace extends SmoothPagedView
return false;
}
});
+
+ restorePendingWidgets(pkgNames);
}
public void removeAbandonedPromise(BubbleTextView abandonedIcon, UserHandleCompat user) {
@@ -4879,7 +4865,7 @@ public class Workspace extends SmoothPagedView
}
public void updatePackageState(final String pkgName, final int state) {
- mapOverShortcuts(MAP_RECURSE, new ShortcutOperator() {
+ mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (info instanceof ShortcutInfo
@@ -4892,10 +4878,44 @@ public class Workspace extends SmoothPagedView
return false;
}
});
+
+ if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
+ // Update any pending widget
+ HashSet<String> packages = new HashSet<>();
+ packages.add(pkgName);
+ restorePendingWidgets(packages);
+ }
+ }
+
+ private void restorePendingWidgets(final Set<String> installedPackaged) {
+ final ContentResolver contentResolver = getContext().getContentResolver();
+ // Iterate non recursively as widgets can't be inside a folder.
+ mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+
+ @Override
+ public boolean evaluate(ItemInfo info, View v, View parent) {
+ if (info instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
+ if (widgetInfo.restoreStatus == LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING
+ && installedPackaged.contains(widgetInfo.providerName.getPackageName())) {
+ // Package installed. Update pending widgets.
+ ContentValues values = new ContentValues();
+ values.put(LauncherSettings.Favorites.RESTORED,
+ LauncherAppWidgetInfo.RESTORE_COMPLETED);
+ String where = BaseColumns._ID + "= ?";
+ String[] args = {Long.toString(widgetInfo.id)};
+ contentResolver.update(LauncherSettings.Favorites.CONTENT_URI,
+ values, where, args);
+ }
+ }
+ // process all the widget
+ return false;
+ }
+ });
}
private void moveToScreen(int page, boolean animate) {
- if (!isSmall()) {
+ if (!workspaceInModalState()) {
if (animate) {
snapToPage(page);
} else {