summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml7
-rw-r--r--WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java7
-rw-r--r--res/layout/user_folder.xml8
-rw-r--r--res/values/dimens.xml1
-rw-r--r--res/values/strings.xml6
-rw-r--r--res/xml/launcher_preferences.xml27
-rw-r--r--src/com/android/launcher3/BubbleTextView.java2
-rw-r--r--src/com/android/launcher3/ButtonDropTarget.java2
-rw-r--r--src/com/android/launcher3/CellLayout.java6
-rw-r--r--src/com/android/launcher3/CommonAppTypeParser.java5
-rw-r--r--src/com/android/launcher3/DragView.java4
-rw-r--r--src/com/android/launcher3/FocusHelper.java2
-rw-r--r--src/com/android/launcher3/Folder.java37
-rw-r--r--src/com/android/launcher3/FolderPagedView.java20
-rw-r--r--src/com/android/launcher3/Hotseat.java10
-rw-r--r--src/com/android/launcher3/IconCache.java18
-rw-r--r--src/com/android/launcher3/Launcher.java85
-rw-r--r--src/com/android/launcher3/LauncherBackupHelper.java10
-rw-r--r--src/com/android/launcher3/LauncherCallbacks.java2
-rw-r--r--src/com/android/launcher3/LauncherFiles.java5
-rw-r--r--src/com/android/launcher3/LauncherModel.java4
-rw-r--r--src/com/android/launcher3/LauncherProvider.java4
-rw-r--r--src/com/android/launcher3/PagedView.java9
-rw-r--r--src/com/android/launcher3/SettingsActivity.java53
-rw-r--r--src/com/android/launcher3/Stats.java80
-rw-r--r--src/com/android/launcher3/Utilities.java17
-rw-r--r--src/com/android/launcher3/WidgetPreviewLoader.java19
-rw-r--r--src/com/android/launcher3/Workspace.java10
-rw-r--r--src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java2
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java93
-rw-r--r--src/com/android/launcher3/allapps/AllAppsGridAdapter.java2
-rw-r--r--src/com/android/launcher3/allapps/AllAppsRecyclerView.java18
-rw-r--r--src/com/android/launcher3/allapps/AlphabeticalAppsList.java146
-rw-r--r--src/com/android/launcher3/allapps/AppSearchManager.java59
-rw-r--r--src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java98
-rw-r--r--src/com/android/launcher3/model/AbstractUserComparator.java67
-rw-r--r--src/com/android/launcher3/model/AppNameComparator.java52
-rw-r--r--src/com/android/launcher3/util/LongArrayMap.java2
-rw-r--r--src/com/android/launcher3/widget/WidgetHostViewLoader.java5
-rw-r--r--src/com/android/launcher3/widget/WidgetsContainerView.java3
40 files changed, 801 insertions, 206 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b61b90c5c..fce469114 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -83,6 +83,7 @@
android:theme="@style/Theme"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="nosensor"
+ android:resumeWhilePausing="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -148,6 +149,12 @@
</intent-filter>
</activity>
+ <activity
+ android:name="com.android.launcher3.SettingsActivity"
+ android:label="@string/settings_button_text"
+ android:autoRemoveFromRecents="true">
+ </activity>
+
<!-- Debugging tools -->
<activity
android:name="com.android.launcher3.MemoryDumpActivity"
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index 96238717e..94159416a 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -1142,6 +1142,11 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
@Override
public boolean enableRotation() {
- return Utilities.isRotationEnabled(getContext());
+ // Check if rotation is enabled for this device.
+ if (Utilities.isRotationAllowedForDevice(getContext()))
+ return true;
+
+ // Check if the user has specifically enabled rotation via preferences.
+ return Utilities.isAllowRotationPrefEnabled(getApplicationContext());
}
}
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 67b69cabf..ecf7def48 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -40,7 +40,7 @@
android:layout_height="match_parent"
android:paddingLeft="4dp"
android:paddingRight="4dp"
- android:paddingTop="4dp"
+ android:paddingTop="8dp"
launcher:pageIndicator="@+id/folder_page_indicator" />
</FrameLayout>
@@ -48,6 +48,7 @@
android:id="@+id/folder_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="false"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:paddingRight="8dp" >
@@ -63,8 +64,8 @@
android:gravity="center_horizontal"
android:hint="@string/folder_hint_text"
android:imeOptions="flagNoExtractUi"
- android:paddingBottom="@dimen/folder_name_padding"
- android:paddingTop="@dimen/folder_name_padding"
+ android:paddingBottom="8dp"
+ android:paddingTop="4dp"
android:singleLine="true"
android:textColor="#ff777777"
android:textColorHighlight="#ffCCCCCC"
@@ -78,6 +79,7 @@
android:layout_height="12dp"
android:layout_gravity="center_vertical"
layout="@layout/page_indicator" />
+
</LinearLayout>
</com.android.launcher3.Folder> \ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 246adcdad..7950862db 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -114,7 +114,6 @@
<!-- Folders -->
<!-- The amount that the preview contents are inset from the preview background -->
<dimen name="folder_preview_padding">4dp</dimen>
- <dimen name="folder_name_padding">10dp</dimen>
<!-- Sizes for managed profile badges -->
<dimen name="profile_badge_size">24dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a8c668d61..440a5378d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -166,6 +166,12 @@
<!-- Text for settings button -->
<string name="settings_button_text">Settings</string>
+ <!-- Strings for settings -->
+ <!-- Title for Allow Rotation setting. [CHAR LIMIT=50] [DO NOT TRANSLATE] -->
+ <string name="allow_rotation_title">Allow rotation</string>
+ <!-- Summary for Allow Rotation setting. [CHAR LIMIT=150] [DO NOT TRANSLATE] -->
+ <string name="allow_rotation_summary">Allow rotation of the home screen</string>
+
<!-- Label on an icon that references an uninstalled package, for which we have no information about when it might be installed. [CHAR_LIMIT=15] -->
<string name="package_state_unknown">Unknown</string>
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
new file mode 100644
index 000000000..f283575f0
--- /dev/null
+++ b/res/xml/launcher_preferences.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <SwitchPreference
+ android:key="pref_allowRotation"
+ android:title="@string/allow_rotation_title"
+ android:summary="@string/allow_rotation_summary"
+ android:defaultValue="@bool/allow_rotation"
+ android:persistent="true"
+ />
+
+</PreferenceScreen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 798eec8e7..314c21f64 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -28,7 +28,6 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.KeyEvent;
@@ -36,7 +35,6 @@ import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.widget.TextView;
-
import com.android.launcher3.IconCache.IconLoadRequest;
import com.android.launcher3.model.PackageItemInfo;
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 4cd28c034..09a71b0cc 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -64,7 +64,7 @@ public abstract class ButtonDropTarget extends TextView
protected Drawable mDrawable;
private AnimatorSet mCurrentColorAnim;
- private ColorMatrix mSrcFilter, mDstFilter, mCurrentFilter;
+ @Thunk ColorMatrix mSrcFilter, mDstFilter, mCurrentFilter;
public ButtonDropTarget(Context context, AttributeSet attrs) {
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index a57c1fe98..b5d0dca24 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -131,10 +131,8 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
private final ClickShadowView mTouchFeedbackView;
- @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
- HashMap<CellLayout.LayoutParams, Animator>();
- private HashMap<View, ReorderPreviewAnimation>
- mShakeAnimators = new HashMap<View, ReorderPreviewAnimation>();
+ @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<>();
+ @Thunk HashMap<View, ReorderPreviewAnimation> mShakeAnimators = new HashMap<>();
private boolean mItemPlacementDirty = false;
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
index 31641799d..5314ecff1 100644
--- a/src/com/android/launcher3/CommonAppTypeParser.java
+++ b/src/com/android/launcher3/CommonAppTypeParser.java
@@ -26,6 +26,7 @@ import android.util.Log;
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.backup.BackupProtos.Favorite;
+import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParserException;
@@ -44,8 +45,8 @@ public class CommonAppTypeParser implements LayoutParserCallback {
private final long mItemId;
- private final int mResId;
- private final Context mContext;
+ @Thunk final int mResId;
+ @Thunk final Context mContext;
ContentValues parsedValues;
Intent parsedIntent;
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index b3323384d..dfa8202a7 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -44,7 +44,7 @@ public class DragView extends View {
private Bitmap mBitmap;
private Bitmap mCrossFadeBitmap;
- private Paint mPaint;
+ @Thunk Paint mPaint;
private int mRegistrationX;
private int mRegistrationY;
@@ -62,7 +62,7 @@ public class DragView extends View {
// size. This is ignored for non-icons.
private float mIntrinsicIconScale = 1f;
- private float[] mCurrentFilter;
+ @Thunk float[] mCurrentFilter;
private ValueAnimator mFilterAnimator;
/**
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index 46e4902f9..70bb01af0 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -426,7 +426,7 @@ public class FocusHelper {
/**
* Private helper method to get the CellLayoutChildren given a CellLayout index.
*/
- private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
+ @Thunk static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
ViewGroup container, int i) {
CellLayout parent = (CellLayout) container.getChildAt(i);
return parent.getShortcutsAndWidgets();
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index ec4ea044c..94f8fc875 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -29,6 +29,7 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
+import android.os.Bundle;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
@@ -44,6 +45,7 @@ import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
@@ -65,7 +67,8 @@ import java.util.Collections;
*/
public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
- View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource {
+ View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource,
+ Stats.LaunchSourceProvider {
private static final String TAG = "Launcher.Folder";
/**
@@ -89,7 +92,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
*/
private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
- public static final int FOOTER_ANIMATION_DURATION = 200;
+ private static final int FOLDER_NAME_ANIMATION_DURATION = 633;
private static final int REORDER_DELAY = 250;
private static final int ON_EXIT_CLOSE_DELAY = 400;
@@ -502,7 +505,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
textAlpha.setStartDelay(mMaterialExpandStagger);
textAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
-
anim.play(drift);
anim.play(iconsAlpha);
anim.play(textAlpha);
@@ -545,7 +547,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
- mFooter.getPaddingLeft() - mFooter.getPaddingRight();
float textWidth = mFolderName.getPaint().measureText(mFolderName.getText().toString());
- mFolderName.setTranslationX((footerWidth - textWidth) / 2);
+ float translation = (footerWidth - textWidth) / 2;
+ mFolderName.setTranslationX(mContent.mIsRtl ? -translation : translation);
mContent.setMarkerScale(0);
// Do not update the flag if we are in drag mode. The flag will be updated, when we
@@ -555,7 +558,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
@Override
public void onAnimationEnd(Animator animation) {
- mFolderName.animate().setDuration(FOOTER_ANIMATION_DURATION).translationX(0);
+ mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
+ .translationX(0)
+ .setInterpolator(Utilities.isLmpOrAbove() ?
+ AnimationUtils.loadInterpolator(mLauncher,
+ android.R.interpolator.fast_out_slow_in)
+ : new LogDecelerateInterpolator(100, 0));
mContent.animateMarkers();
if (updateAnimationFlag) {
@@ -917,7 +925,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
View v = list.get(i);
ItemInfo info = (ItemInfo) v.getTag();
LauncherModel.addItemToDatabase(mLauncher, info, mInfo.id, 0,
- info.cellX, info.cellY);
+ info.cellX, info.cellY);
}
}
@@ -1032,6 +1040,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mContent.setFixedSize(contentWidth, contentHeight);
mContentWrapper.measure(contentAreaWidthSpec, contentAreaHeightSpec);
+
+ if (mContent.getChildCount() > 0) {
+ int cellIconGap = (mContent.getPageAt(0).getCellWidth()
+ - mLauncher.getDeviceProfile().iconSizePx) / 2;
+ mFooter.setPadding(mContent.getPaddingLeft() + cellIconGap,
+ mFooter.getPaddingTop(),
+ mContent.getPaddingRight() + cellIconGap,
+ mFooter.getPaddingBottom());
+ }
mFooter.measure(contentAreaWidthSpec,
MeasureSpec.makeMeasureSpec(mFooterHeight, MeasureSpec.EXACTLY));
@@ -1323,6 +1340,14 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
outRect.right += mScrollAreaOffset;
}
+ @Override
+ public void fillInLaunchSourceData(Bundle sourceData) {
+ // Fill in from the folder icon's launch source provider first
+ Stats.LaunchSourceUtils.populateSourceDataFromAncestorProvider(mFolderIcon, sourceData);
+ sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, Stats.SUB_CONTAINER_FOLDER);
+ sourceData.putInt(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE, mContent.getCurrentPage());
+ }
+
private class OnScrollHintListener implements OnAlarmListener {
private final DragObject mDragObject;
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 0bd6501ed..7d90ba2f7 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -24,6 +24,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
@@ -46,7 +47,12 @@ public class FolderPagedView extends PagedView {
private static final int START_VIEW_REORDER_DELAY = 30;
private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
- private static final int PAGE_INDICATOR_ANIMATION_DELAY = 150;
+ private static final int PAGE_INDICATOR_ANIMATION_START_DELAY = 300;
+ private static final int PAGE_INDICATOR_ANIMATION_STAGGERED_DELAY = 150;
+ private static final int PAGE_INDICATOR_ANIMATION_DURATION = 400;
+
+ // This value approximately overshoots to 1.5 times the original size.
+ private static final float PAGE_INDICATOR_OVERSHOOT_TENSION = 4.9f;
/**
* Fraction of the width to scroll when showing the next page hint.
@@ -274,6 +280,7 @@ public class FolderPagedView extends PagedView {
arrangeChildren(list, itemCount, true);
}
+ @SuppressLint("RtlHardcoded")
private void arrangeChildren(ArrayList<View> list, int itemCount, boolean saveChanges) {
ArrayList<CellLayout> pages = new ArrayList<CellLayout>();
for (int i = 0; i < getChildCount(); i++) {
@@ -340,7 +347,9 @@ public class FolderPagedView extends PagedView {
// Update footer
mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
- mFolder.mFolderName.setGravity(getPageCount() > 1 ? Gravity.START : Gravity.CENTER_HORIZONTAL);
+ // Set the gravity as LEFT or RIGHT instead of START, as START depends on the actual text.
+ mFolder.mFolderName.setGravity(getPageCount() > 1 ?
+ (mIsRtl ? Gravity.RIGHT : Gravity.LEFT) : Gravity.CENTER_HORIZONTAL);
}
public int getDesiredWidth() {
@@ -645,12 +654,13 @@ public class FolderPagedView extends PagedView {
public void animateMarkers() {
int count = mPageIndicator.getChildCount();
- OvershootInterpolator interpolator = new OvershootInterpolator(4);
+ Interpolator interpolator = new OvershootInterpolator(PAGE_INDICATOR_OVERSHOOT_TENSION);
for (int i = 0; i < count; i++) {
mPageIndicator.getChildAt(i).animate().scaleX(1).scaleY(1)
.setInterpolator(interpolator)
- .setDuration(Folder.FOOTER_ANIMATION_DURATION)
- .setStartDelay(PAGE_INDICATOR_ANIMATION_DELAY * i);
+ .setDuration(PAGE_INDICATOR_ANIMATION_DURATION)
+ .setStartDelay(PAGE_INDICATOR_ANIMATION_STAGGERED_DELAY * i
+ + PAGE_INDICATOR_ANIMATION_START_DELAY);
}
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index ce33164fa..6f097449c 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -19,15 +19,16 @@ package com.android.launcher3;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
-public class Hotseat extends FrameLayout {
+public class Hotseat extends FrameLayout
+ implements Stats.LaunchSourceProvider{
private CellLayout mContent;
@@ -160,4 +161,9 @@ public class Hotseat extends FrameLayout {
}
return false;
}
+
+ @Override
+ public void fillInLaunchSourceData(Bundle sourceData) {
+ sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOTSEAT);
+ }
}
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 6dfca9ef3..a16067d16 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -69,7 +69,7 @@ public class IconCache {
private static final int LOW_RES_SCALE_FACTOR = 8;
- private static final Object ICON_UPDATE_TOKEN = new Object();
+ @Thunk static final Object ICON_UPDATE_TOKEN = new Object();
@Thunk static class CacheEntry {
public Bitmap icon;
@@ -79,18 +79,18 @@ public class IconCache {
}
private final HashMap<UserHandleCompat, Bitmap> mDefaultIcons = new HashMap<>();
- private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
+ @Thunk final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
private final Context mContext;
private final PackageManager mPackageManager;
- private final UserManagerCompat mUserManager;
+ @Thunk final UserManagerCompat mUserManager;
private final LauncherAppsCompat mLauncherApps;
private final HashMap<ComponentKey, CacheEntry> mCache =
new HashMap<ComponentKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
private final int mIconDpi;
- private final IconDB mIconDb;
+ @Thunk final IconDB mIconDb;
- private final Handler mWorkerHandler;
+ @Thunk final Handler mWorkerHandler;
public IconCache(Context context, InvariantDeviceProfile inv) {
ActivityManager activityManager =
@@ -320,7 +320,7 @@ public class IconCache {
}
}
- private void addIconToDBAndMemCache(LauncherActivityInfoCompat app, PackageInfo info,
+ @Thunk void addIconToDBAndMemCache(LauncherActivityInfoCompat app, PackageInfo info,
long userSerial) {
// Reuse the existing entry if it already exists in the DB. This ensures that we do not
// create bitmap if it was already created during loader.
@@ -342,7 +342,7 @@ public class IconCache {
SQLiteDatabase.CONFLICT_REPLACE);
}
- private ContentValues updateCacheAndGetContentValues(LauncherActivityInfoCompat app,
+ @Thunk ContentValues updateCacheAndGetContentValues(LauncherActivityInfoCompat app,
boolean replaceExisting) {
final ComponentKey key = new ComponentKey(app.getComponentName(), app.getUser());
CacheEntry entry = null;
@@ -688,14 +688,14 @@ public class IconCache {
* LauncherActivityInfoCompat list. Items are updated/added one at a time, so that the
* worker thread doesn't get blocked.
*/
- private class SerializedIconUpdateTask implements Runnable {
+ @Thunk class SerializedIconUpdateTask implements Runnable {
private final long mUserSerial;
private final HashMap<String, PackageInfo> mPkgInfoMap;
private final Stack<LauncherActivityInfoCompat> mAppsToAdd;
private final Stack<LauncherActivityInfoCompat> mAppsToUpdate;
private final HashSet<String> mUpdatedPackages = new HashSet<String>();
- private SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
+ @Thunk SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
Stack<LauncherActivityInfoCompat> appsToAdd,
Stack<LauncherActivityInfoCompat> appsToUpdate) {
mUserSerial = userSerial;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5dac3b3da..867a6e71d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -100,6 +100,7 @@ import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.PagedView.PageSwitchListener;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AppSearchManager;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -218,7 +219,8 @@ public class Launcher extends Activity
public static final String USER_HAS_MIGRATED = "launcher.user_migrated_from_old_data";
/** The different states that Launcher can be in. */
- enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED };
+ enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED }
+
@Thunk State mState = State.WORKSPACE;
@Thunk LauncherStateTransitionAnimation mStateTransitionAnimation;
@@ -263,7 +265,7 @@ public class Launcher extends Activity
private int[] mTmpAddItemCellCoordinates = new int[2];
- private Hotseat mHotseat;
+ @Thunk Hotseat mHotseat;
private ViewGroup mOverviewPanel;
private View mAllAppsButton;
@@ -400,6 +402,24 @@ public class Launcher extends Activity
FocusIndicatorView mFocusHandler;
+ @Thunk boolean mRotationEnabled = false;
+ private boolean mPreferenceObserverRegistered = false;
+
+ final private SharedPreferences.OnSharedPreferenceChangeListener mSettingsObserver =
+ new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (Utilities.ALLOW_ROTATION_PREFERENCE_KEY.equals(key)) {
+ if (mRotationEnabled = sharedPreferences.getBoolean(
+ Utilities.ALLOW_ROTATION_PREFERENCE_KEY, false)) {
+ unlockScreenOrientation(true);
+ } else {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+ }
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG_STRICT_MODE) {
@@ -499,7 +519,19 @@ public class Launcher extends Activity
IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
registerReceiver(mCloseSystemDialogsReceiver, filter);
- // On large interfaces, we want the screen to auto-rotate based on the current orientation
+ mRotationEnabled = Utilities.isRotationAllowedForDevice(getApplicationContext());
+ // In case we are on a device with locked rotation, we should look at preferences to check
+ // if the user has specifically allowed rotation.
+ if (!mRotationEnabled) {
+ getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
+ Context.MODE_MULTI_PROCESS).registerOnSharedPreferenceChangeListener(
+ mSettingsObserver);
+ mPreferenceObserverRegistered = true;
+ mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
+ }
+
+ // On large interfaces, or on devices that a user has specifically enabled screen rotation,
+ // we want the screen to auto-rotate based on the current orientation
unlockScreenOrientation(true);
if (mLauncherCallbacks != null) {
@@ -552,6 +584,11 @@ public class Launcher extends Activity
}
}
}
+
+ @Override
+ public void setSearchManager(AppSearchManager manager) {
+ mAppsView.setSearchManager(manager);
+ }
});
mLauncherCallbacks.setLauncherSearchCallback(new Launcher.LauncherSearchCallbacks() {
private boolean mImportanceStored = false;
@@ -1127,6 +1164,11 @@ public class Launcher extends Activity
* Called to dismiss all apps if it is showing.
*/
public void dismissAllApps();
+
+ /**
+ * Sets the search manager to be used for app search.
+ */
+ public void setSearchManager(AppSearchManager manager);
}
public interface LauncherSearchCallbacks {
@@ -1192,8 +1234,11 @@ public class Launcher extends Activity
protected boolean hasSettings() {
if (mLauncherCallbacks != null) {
return mLauncherCallbacks.hasSettings();
+ } else {
+ // On devices with a locked orientation, we will at least have the allow rotation
+ // setting.
+ return !Utilities.isRotationAllowedForDevice(this);
}
- return false;
}
public void addToCustomContentPage(View customContent,
@@ -1486,7 +1531,6 @@ public class Launcher extends Activity
* Add a shortcut to the workspace.
*
* @param data The intent describing the shortcut.
- * @param cellInfo The position on screen where to create the shortcut.
*/
private void completeAddShortcut(Intent data, long container, long screenId, int cellX,
int cellY) {
@@ -1975,6 +2019,13 @@ public class Launcher extends Activity
public void onDestroy() {
super.onDestroy();
+ if (mPreferenceObserverRegistered) {
+ getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
+ Context.MODE_MULTI_PROCESS).unregisterOnSharedPreferenceChangeListener(
+ mSettingsObserver);
+ mPreferenceObserverRegistered = false;
+ }
+
// Remove all pending runnables
mHandler.removeMessages(ADVANCE_MSG);
mHandler.removeMessages(0);
@@ -2497,13 +2548,6 @@ public class Launcher extends Activity
}
}
- public void onClickPagedViewIcon(View v) {
- startAppShortcutOrInfoActivity(v);
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onClickPagedViewIcon(v);
- }
- }
-
@SuppressLint("ClickableViewAccessibility")
public boolean onTouch(View v, MotionEvent event) {
return false;
@@ -2662,7 +2706,7 @@ public class Launcher extends Activity
}
boolean success = startActivitySafely(v, intent, tag);
- mStats.recordLaunch(intent, shortcut);
+ mStats.recordLaunch(v, intent, shortcut);
if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
@@ -2757,6 +2801,8 @@ public class Launcher extends Activity
if (LOGD) Log.d(TAG, "onClickSettingsButton");
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onClickSettingsButton(v);
+ } else {
+ showSettingsActivity();
}
}
@@ -2882,7 +2928,7 @@ public class Launcher extends Activity
}
}
- boolean startActivity(View v, Intent intent, Object tag) {
+ private boolean startActivity(View v, Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
// Only launch using the new animation if the shortcut has not opted out (this is a
@@ -2953,7 +2999,7 @@ public class Launcher extends Activity
return false;
}
- boolean startActivitySafely(View v, Intent intent, Object tag) {
+ private 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();
@@ -4364,7 +4410,7 @@ public class Launcher extends Activity
}
public void lockScreenOrientation() {
- if (Utilities.isRotationEnabled(this)) {
+ if (mRotationEnabled) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
.getConfiguration().orientation));
@@ -4373,8 +4419,9 @@ public class Launcher extends Activity
}
}
}
+
public void unlockScreenOrientation(boolean immediate) {
- if (Utilities.isRotationEnabled(this)) {
+ if (mRotationEnabled) {
if (immediate) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
} else {
@@ -4479,6 +4526,10 @@ public class Launcher extends Activity
editor.apply();
}
+ private void showSettingsActivity() {
+ startActivity(new Intent(this, SettingsActivity.class));
+ }
+
/**
* To be overridden by subclasses to indicate that there is an in-activity full-screen intro
* screen that must be displayed and dismissed.
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index af4101221..b40ace3fb 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -51,13 +51,13 @@ import com.android.launcher3.backup.BackupProtos.Screen;
import com.android.launcher3.backup.BackupProtos.Widget;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.Thunk;
import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
import com.google.protobuf.nano.MessageNano;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -135,7 +135,7 @@ public class LauncherBackupHelper implements BackupHelper {
private static final int SCREEN_RANK_INDEX = 2;
- private final Context mContext;
+ @Thunk final Context mContext;
private final HashSet<String> mExistingKeys;
private final ArrayList<Key> mKeys;
private final ItemTypeMatcher[] mItemTypeMatchers;
@@ -1157,15 +1157,15 @@ public class LauncherBackupHelper implements BackupHelper {
.getSerialNumberForUser(UserHandleCompat.myUserHandle());
}
- private class InvalidBackupException extends IOException {
+ @Thunk class InvalidBackupException extends IOException {
private static final long serialVersionUID = 8931456637211665082L;
- private InvalidBackupException(Throwable cause) {
+ @Thunk InvalidBackupException(Throwable cause) {
super(cause);
}
- public InvalidBackupException(String reason) {
+ @Thunk InvalidBackupException(String reason) {
super(reason);
}
}
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index a5f36ba93..70e400bca 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -56,6 +56,8 @@ public interface LauncherCallbacks {
public void bindAllApplications(ArrayList<AppInfo> apps);
public void onClickFolderIcon(View v);
public void onClickAppShortcut(View v);
+
+ @Deprecated
public void onClickPagedViewIcon(View v);
public void onClickWallpaperPicker(View v);
public void onClickSettingsButton(View v);
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index c08cd0bf5..ec4e4f942 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -26,6 +26,8 @@ public class LauncherFiles {
public static final String WIDGET_PREVIEWS_DB = "widgetpreviews.db";
public static final String APP_ICONS_DB = "app_icons.db";
+ public static final String ROTATION_PREF_FILE = "com.android.launcher3.rotation.prefs";
+
public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
DEFAULT_WALLPAPER_THUMBNAIL,
DEFAULT_WALLPAPER_THUMBNAIL_OLD,
@@ -35,7 +37,8 @@ public class LauncherFiles {
WALLPAPER_IMAGES_DB,
WIDGET_PREVIEWS_DB,
MANAGED_USER_PREFERENCES_KEY,
- APP_ICONS_DB));
+ APP_ICONS_DB,
+ ROTATION_PREF_FILE));
// TODO: Delete these files on upgrade
public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList(
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 224ebbf89..776c2bd63 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -275,7 +275,7 @@ public class LauncherModel extends BroadcastReceiver
/**
* Runs the specified runnable after the loader is complete
*/
- private void runAfterBindCompletes(Runnable r) {
+ @Thunk void runAfterBindCompletes(Runnable r) {
if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) {
synchronized (mBindCompleteRunnables) {
mBindCompleteRunnables.add(r);
@@ -3350,7 +3350,7 @@ public class LauncherModel extends BroadcastReceiver
*
* @see #loadAndBindWidgetsAndShortcuts
*/
- private WidgetsModel createWidgetsModel(Context context, boolean refresh) {
+ @Thunk WidgetsModel createWidgetsModel(Context context, boolean refresh) {
PackageManager packageManager = context.getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 27511527d..45070d190 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -88,7 +88,7 @@ public class LauncherProvider extends ContentProvider {
static final Uri CONTENT_APPWIDGET_RESET_URI =
Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
- private DatabaseHelper mOpenHelper;
+ @Thunk DatabaseHelper mOpenHelper;
@Override
public boolean onCreate() {
@@ -665,7 +665,7 @@ public class LauncherProvider extends ContentProvider {
* Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
* launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
*/
- private void convertShortcutsToLauncherActivities(SQLiteDatabase db) {
+ @Thunk void convertShortcutsToLauncherActivities(SQLiteDatabase db) {
db.beginTransaction();
Cursor c = null;
SQLiteStatement updateStmt = null;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9271e8b15..18832c680 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -22,11 +22,13 @@ import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -45,9 +47,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
-
import com.android.launcher3.util.Thunk;
-
import java.util.ArrayList;
/**
@@ -186,7 +186,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// We use the min scale to determine how much to expand the actually PagedView measured
// dimensions such that when we are zoomed out, the view is not clipped
private static int REORDERING_DROP_REPOSITION_DURATION = 200;
- private static int REORDERING_REORDER_REPOSITION_DURATION = 300;
+ @Thunk static int REORDERING_REORDER_REPOSITION_DURATION = 300;
private static int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80;
private float mMinScale = 1f;
@@ -956,7 +956,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
return 0;
}
- private void updateMaxScrollX() {
+ @Thunk void updateMaxScrollX() {
int childCount = getChildCount();
if (childCount > 0) {
final int index = mIsRtl ? 0 : childCount - 1;
@@ -2322,6 +2322,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
private static final int ANIM_TAG_KEY = 100;
/* Accessibility */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
new file mode 100644
index 000000000..a1da1b6fd
--- /dev/null
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+/**
+ * Settings activity for Launcher. Currently implements the following setting:
+ * LockToPortrait
+ */
+public class SettingsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Display the fragment as the main content.
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new LauncherSettingsFragment())
+ .commit();
+ }
+
+ /**
+ * This fragment shows the launcher preferences.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LauncherSettingsFragment extends PreferenceFragment {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getPreferenceManager().setSharedPreferencesMode(Context.MODE_PRIVATE);
+ getPreferenceManager().setSharedPreferencesName(LauncherFiles.ROTATION_PREF_FILE);
+ addPreferencesFromResource(R.xml.launcher_preferences);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index 9d06f755f..cb0e252b2 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -20,9 +20,63 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Bundle;
import android.util.Log;
+import android.view.View;
+import android.view.ViewParent;
public class Stats {
+
+ /**
+ * Implemented by containers to provide a launch source for a given child.
+ */
+ public interface LaunchSourceProvider {
+ void fillInLaunchSourceData(Bundle sourceData);
+ }
+
+ /**
+ * Helpers to add the source to a launch intent.
+ */
+ public static class LaunchSourceUtils {
+ /**
+ * Create a default bundle for LaunchSourceProviders to fill in their data.
+ */
+ public static Bundle createSourceData() {
+ Bundle sourceData = new Bundle();
+ sourceData.putString(SOURCE_EXTRA_CONTAINER, CONTAINER_HOMESCREEN);
+ // Have default container/sub container pages
+ sourceData.putInt(SOURCE_EXTRA_CONTAINER_PAGE, 0);
+ sourceData.putInt(SOURCE_EXTRA_SUB_CONTAINER_PAGE, 0);
+ return sourceData;
+ }
+
+ /**
+ * Finds the next launch source provider in the parents of the view hierarchy and populates
+ * the source data from that provider.
+ */
+ public static void populateSourceDataFromAncestorProvider(View v, Bundle sourceData) {
+ if (v == null) {
+ return;
+ }
+
+ Stats.LaunchSourceProvider provider = null;
+ ViewParent parent = v.getParent();
+ while (parent != null && parent instanceof View) {
+ if (parent instanceof Stats.LaunchSourceProvider) {
+ provider = (Stats.LaunchSourceProvider) parent;
+ break;
+ }
+ parent = parent.getParent();
+ }
+
+ if (provider != null) {
+ provider.fillInLaunchSourceData(sourceData);
+ } else if (LauncherAppState.isDogfoodBuild()) {
+ throw new RuntimeException("Expected LaunchSourceProvider");
+ }
+ }
+ }
+
private static final boolean DEBUG_BROADCASTS = false;
public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
@@ -31,6 +85,22 @@ public class Stats {
public static final String EXTRA_SCREEN = "screen";
public static final String EXTRA_CELLX = "cellX";
public static final String EXTRA_CELLY = "cellY";
+ public static final String EXTRA_SOURCE = "source";
+
+ public static final String SOURCE_EXTRA_CONTAINER = "container";
+ public static final String SOURCE_EXTRA_CONTAINER_PAGE = "container_page";
+ public static final String SOURCE_EXTRA_SUB_CONTAINER = "sub_container";
+ public static final String SOURCE_EXTRA_SUB_CONTAINER_PAGE = "sub_container_page";
+
+ public static final String CONTAINER_SEARCH_BOX = "search_box";
+ public static final String CONTAINER_ALL_APPS = "all_apps";
+ public static final String CONTAINER_HOMESCREEN = "homescreen"; // aka. Workspace
+ public static final String CONTAINER_HOTSEAT = "hotseat";
+
+ public static final String SUB_CONTAINER_FOLDER = "folder";
+ public static final String SUB_CONTAINER_ALL_APPS_A_Z = "a-z";
+ public static final String SUB_CONTAINER_ALL_APPS_PREDICTION = "prediction";
+ public static final String SUB_CONTAINER_ALL_APPS_SEARCH = "search";
private final Launcher mLauncher;
private final String mLaunchBroadcastPermission;
@@ -56,11 +126,7 @@ public class Stats {
}
}
- public void recordLaunch(Intent intent) {
- recordLaunch(intent, null);
- }
-
- public void recordLaunch(Intent intent, ShortcutInfo shortcut) {
+ public void recordLaunch(View v, Intent intent, ShortcutInfo shortcut) {
intent = new Intent(intent);
intent.setSourceBounds(null);
@@ -72,6 +138,10 @@ public class Stats {
.putExtra(EXTRA_CELLX, shortcut.cellX)
.putExtra(EXTRA_CELLY, shortcut.cellY);
}
+
+ Bundle sourceExtras = LaunchSourceUtils.createSourceData();
+ LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras);
+ broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras);
mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
}
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 256eba020..a9cbf6970 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -25,6 +25,7 @@ import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -67,6 +68,7 @@ import java.util.regex.Pattern;
* Various utilities shared amongst the Launcher's classes.
*/
public final class Utilities {
+
private static final String TAG = "Launcher.Utilities";
private static int sIconWidth = -1;
@@ -93,6 +95,8 @@ public final class Utilities {
static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
+ public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
+
/**
* Returns a FastBitmapDrawable with the icon, accurately sized.
*/
@@ -114,10 +118,15 @@ public final class Utilities {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
- public static boolean isRotationEnabled(Context c) {
- boolean enableRotation = sForceEnableRotation ||
- c.getResources().getBoolean(R.bool.allow_rotation);
- return enableRotation;
+ public static boolean isAllowRotationPrefEnabled(Context context) {
+ SharedPreferences sharedPrefs = context.getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
+ Context.MODE_MULTI_PROCESS);
+ boolean allowRotationPref = sharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, false);
+ return sForceEnableRotation || allowRotationPref;
+ }
+
+ public static boolean isRotationAllowedForDevice(Context context) {
+ return sForceEnableRotation || context.getResources().getBoolean(R.bool.allow_rotation);
}
/**
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index e8cc48685..a62177142 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -56,7 +56,7 @@ public class WidgetPreviewLoader {
* Weak reference objects, do not prevent their referents from being made finalizable,
* finalized, and then reclaimed.
*/
- private Set<Bitmap> mUnusedBitmaps =
+ @Thunk Set<Bitmap> mUnusedBitmaps =
Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
private final Context mContext;
@@ -67,7 +67,7 @@ public class WidgetPreviewLoader {
private final InvariantDeviceProfile mDeviceProfile;
private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
- private final Handler mWorkerHandler;
+ @Thunk final Handler mWorkerHandler;
public WidgetPreviewLoader(Context context, InvariantDeviceProfile inv, IconCache iconCache) {
mContext = context;
@@ -290,7 +290,7 @@ public class WidgetPreviewLoader {
/**
* Reads the preview bitmap from the DB or null if the preview is not in the DB.
*/
- private Bitmap readFromDb(WidgetCacheKey key, Bitmap recycle, PreviewLoadTask loadTask) {
+ @Thunk Bitmap readFromDb(WidgetCacheKey key, Bitmap recycle, PreviewLoadTask loadTask) {
Cursor cursor = null;
try {
cursor = mDb.getReadableDatabase().query(
@@ -329,7 +329,7 @@ public class WidgetPreviewLoader {
return null;
}
- private Bitmap generatePreview(Launcher launcher, Object info, Bitmap recycle,
+ @Thunk Bitmap generatePreview(Launcher launcher, Object info, Bitmap recycle,
int previewWidth, int previewHeight) {
if (info instanceof LauncherAppWidgetProviderInfo) {
return generateWidgetPreview(launcher, (LauncherAppWidgetProviderInfo) info,
@@ -512,7 +512,7 @@ public class WidgetPreviewLoader {
/**
* @return an array of containing versionCode and lastUpdatedTime for the package.
*/
- private long[] getPackageVersion(String packageName) {
+ @Thunk long[] getPackageVersion(String packageName) {
synchronized (mPackageVersions) {
long[] versions = mPackageVersions.get(packageName);
if (versions == null) {
@@ -561,14 +561,13 @@ public class WidgetPreviewLoader {
}
public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap> {
-
- private final WidgetCacheKey mKey;
+ @Thunk final WidgetCacheKey mKey;
private final Object mInfo;
private final int mPreviewHeight;
private final int mPreviewWidth;
private final WidgetCell mCaller;
- private long[] mVersions;
- private Bitmap mBitmapToRecycle;
+ @Thunk long[] mVersions;
+ @Thunk Bitmap mBitmapToRecycle;
PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth,
int previewHeight, WidgetCell caller) {
@@ -674,7 +673,7 @@ public class WidgetPreviewLoader {
private static final class WidgetCacheKey extends ComponentKey {
// TODO: remove dependency on size
- private final String size;
+ @Thunk final String size;
public WidgetCacheKey(ComponentName componentName, UserHandleCompat user, String size) {
super(componentName, user);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6d5affb59..193a0af6f 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -28,6 +28,7 @@ import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -42,6 +43,7 @@ import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcelable;
@@ -86,7 +88,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class Workspace extends PagedView
implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
- Insettable, UninstallSource, AccessibilityDragSource {
+ Insettable, UninstallSource, AccessibilityDragSource, Stats.LaunchSourceProvider {
private static final String TAG = "Launcher.Workspace";
private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
@@ -4461,6 +4463,12 @@ public class Workspace extends PagedView
mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
}
+ @Override
+ public void fillInLaunchSourceData(Bundle sourceData) {
+ sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN);
+ sourceData.putInt(Stats.SOURCE_EXTRA_CONTAINER_PAGE, getCurrentPage());
+ }
+
/**
* Used as a workaround to ensure that the AppWidgetService receives the
* PACKAGE_ADDED broadcast before updating widgets.
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 93cf8d050..3c49ccc41 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -251,7 +251,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
return actions;
}
- private void performResizeAction(int action, View host, LauncherAppWidgetInfo info) {
+ @Thunk void performResizeAction(int action, View host, LauncherAppWidgetInfo info) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) host.getLayoutParams();
CellLayout layout = (CellLayout) host.getParent().getParent();
layout.markCellsAsUnoccupiedForView(host);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index d81f97f24..9386500be 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
+import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextWatcher;
@@ -41,6 +42,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.TextView;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.BaseContainerView;
import com.android.launcher3.BubbleTextView;
@@ -54,15 +56,16 @@ import com.android.launcher3.Folder;
import com.android.launcher3.Insettable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherTransitionable;
import com.android.launcher3.R;
+import com.android.launcher3.Stats;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.AppSearchManager.AppSearchResultCallback;
import com.android.launcher3.util.Thunk;
+import java.util.ArrayList;
import java.util.List;
-import java.util.regex.Pattern;
/**
@@ -171,7 +174,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
TextWatcher, TextView.OnEditorActionListener, LauncherTransitionable,
AlphabeticalAppsList.AdapterChangedCallback, AllAppsGridAdapter.PredictionBarSpacerCallbacks,
View.OnTouchListener, View.OnClickListener, View.OnLongClickListener,
- ViewTreeObserver.OnPreDrawListener {
+ ViewTreeObserver.OnPreDrawListener, AppSearchResultCallback, Stats.LaunchSourceProvider {
public static final boolean GRID_MERGE_SECTIONS = true;
@@ -183,8 +186,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private static final int FADE_OUT_DURATION = 100;
private static final int SEARCH_TRANSLATION_X_DP = 18;
- private static final Pattern SPLIT_PATTERN = Pattern.compile("[\\s|\\p{javaSpaceChar}]+");
-
@Thunk Launcher mLauncher;
@Thunk AlphabeticalAppsList mApps;
private LayoutInflater mLayoutInflater;
@@ -192,14 +193,14 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private RecyclerView.LayoutManager mLayoutManager;
private RecyclerView.ItemDecoration mItemDecoration;
- private FrameLayout mContentView;
+ @Thunk FrameLayout mContentView;
@Thunk AllAppsRecyclerView mAppsRecyclerView;
- private ViewGroup mPredictionBarView;
+ @Thunk ViewGroup mPredictionBarView;
private View mHeaderView;
- private View mSearchBarContainerView;
+ @Thunk View mSearchBarContainerView;
private View mSearchButtonView;
private View mDismissSearchButtonView;
- private AllAppsSearchEditView mSearchBarEditView;
+ @Thunk AllAppsSearchEditView mSearchBarEditView;
private HeaderElevationController mElevationController;
@@ -216,11 +217,13 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private int mContainerInset;
private int mPredictionBarHeight;
private int mLastRecyclerViewScrollPos = -1;
- private boolean mFocusPredictionBarOnFirstBind;
+ @Thunk boolean mFocusPredictionBarOnFirstBind;
private CheckLongPressHelper mPredictionIconCheckForLongPress;
private View mPredictionIconUnderTouch;
+ private AppSearchManager mSearchManager;
+
public AllAppsContainerView(Context context) {
this(context, null);
}
@@ -231,7 +234,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- LauncherAppState app = LauncherAppState.getInstance();
Resources res = context.getResources();
mLauncher = (Launcher) context;
@@ -258,6 +260,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mContentMarginStart = mAdapter.getContentMarginStart();
mApps.setAdapter(mAdapter);
+ mSearchManager = mApps.newSimpleAppSearchManager();
}
/**
@@ -281,6 +284,11 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mApps.addApps(apps);
}
+ public void setSearchManager(AppSearchManager searchManager) {
+ mSearchManager.cancel(true);
+ mSearchManager = searchManager;
+ }
+
/**
* Updates existing apps in the list
*/
@@ -664,45 +672,26 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public void afterTextChanged(final Editable s) {
String queryText = s.toString();
if (queryText.isEmpty()) {
- mApps.setFilter(null);
+ mSearchManager.cancel(true);
+ mApps.setOrderedFilter(null);
} else {
String formatStr = getResources().getString(R.string.all_apps_no_search_results);
mAdapter.setEmptySearchText(String.format(formatStr, queryText));
- // Do an intersection of the words in the query and each title, and filter out all the
- // apps that don't match all of the words in the query.
- final String queryTextLower = queryText.toLowerCase();
- final String[] queryWords = SPLIT_PATTERN.split(queryTextLower);
- mApps.setFilter(new AlphabeticalAppsList.Filter() {
- @Override
- public boolean retainApp(AppInfo info, String sectionName) {
- if (sectionName.toLowerCase().contains(queryTextLower)) {
- return true;
- }
- String title = info.title.toString();
- String[] words = SPLIT_PATTERN.split(title.toLowerCase());
- for (int qi = 0; qi < queryWords.length; qi++) {
- boolean foundMatch = false;
- for (int i = 0; i < words.length; i++) {
- if (words[i].startsWith(queryWords[qi])) {
- foundMatch = true;
- break;
- }
- }
- if (!foundMatch) {
- // If there is a word in the query that does not match any words in this
- // title, so skip it.
- return false;
- }
- }
- return true;
- }
- });
+ mSearchManager.cancel(false);
+ mSearchManager.doSearch(queryText, this);
}
scrollToTop();
}
@Override
+ public void onSearchResult(ArrayList<ComponentName> apps) {
+ if (apps != null) {
+ mApps.setOrderedFilter(apps);
+ }
+ }
+
+ @Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (ALLOW_SINGLE_APP_LAUNCH && actionId == EditorInfo.IME_ACTION_DONE) {
// Skip the quick-launch if there isn't exactly one item
@@ -796,7 +785,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
* recycler view.
*/
private boolean handleTouchEvent(MotionEvent ev) {
- LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = mLauncher.getDeviceProfile();
int x = (int) ev.getX();
int y = (int) ev.getY();
@@ -884,6 +872,15 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
return false;
}
+ @Override
+ public void fillInLaunchSourceData(Bundle sourceData) {
+ // Since the other cases are caught by the AllAppsRecyclerView LaunchSourceProvider, we just
+ // handle the prediction bar icons here
+ sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
+ sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+ Stats.SUB_CONTAINER_ALL_APPS_PREDICTION);
+ }
+
/**
* Returns the predicted app in the prediction bar given a set of local coordinates.
*/
@@ -919,6 +916,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
* Shows the search field.
*/
private void showSearchField() {
+ mSearchManager.connect();
+
// Show the search bar and focus the search
final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
getContext().getResources().getDisplayMetrics());
@@ -948,7 +947,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
/**
* Hides the search field.
*/
- private void hideSearchField(boolean animated, final boolean returnFocusToRecyclerView) {
+ @Thunk void hideSearchField(boolean animated, final boolean returnFocusToRecyclerView) {
+ mSearchManager.cancel(true);
+
final boolean resetTextField = mSearchBarEditView.getText().toString().length() > 0;
final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
getContext().getResources().getDisplayMetrics());
@@ -966,7 +967,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
if (resetTextField) {
mSearchBarEditView.setText("");
}
- mApps.setFilter(null);
+ mApps.setOrderedFilter(null);
if (returnFocusToRecyclerView) {
mAppsRecyclerView.requestFocus();
}
@@ -983,7 +984,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
if (resetTextField) {
mSearchBarEditView.setText("");
}
- mApps.setFilter(null);
+ mApps.setOrderedFilter(null);
mSearchButtonView.setAlpha(1f);
mSearchButtonView.setTranslationX(0f);
if (returnFocusToRecyclerView) {
@@ -1011,7 +1012,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
/**
* Returns an input method manager.
*/
- private InputMethodManager getInputMethodManager() {
+ @Thunk InputMethodManager getInputMethodManager() {
return (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index e010270ce..307d9403d 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -288,7 +288,7 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
private GridLayoutManager mGridLayoutMgr;
private GridSpanSizer mGridSizer;
private GridItemDecoration mItemDecoration;
- private PredictionBarSpacerCallbacks mPredictionBarCb;
+ @Thunk PredictionBarSpacerCallbacks mPredictionBarCb;
private View.OnTouchListener mTouchListener;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index cc5add3b2..e1b5d918e 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -18,14 +18,15 @@ package com.android.launcher3.allapps;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
-
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.Stats;
import com.android.launcher3.Utilities;
import java.util.List;
@@ -33,7 +34,8 @@ import java.util.List;
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
-public class AllAppsRecyclerView extends BaseRecyclerView {
+public class AllAppsRecyclerView extends BaseRecyclerView
+ implements Stats.LaunchSourceProvider {
private AlphabeticalAppsList mApps;
private int mNumAppsPerRow;
@@ -125,6 +127,18 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
addOnItemTouchListener(this);
}
+ @Override
+ public void fillInLaunchSourceData(Bundle sourceData) {
+ sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
+ if (mApps.hasFilter()) {
+ sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+ Stats.SUB_CONTAINER_ALL_APPS_SEARCH);
+ } else {
+ sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+ Stats.SUB_CONTAINER_ALL_APPS_A_Z);
+ }
+ }
+
/**
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 3d1503d46..e284f77c4 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -1,15 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.launcher3.allapps;
import android.content.ComponentName;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.model.AbstractUserComparator;
import com.android.launcher3.model.AppNameComparator;
+import com.android.launcher3.util.Thunk;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -25,6 +46,7 @@ public class AlphabeticalAppsList {
public static final String TAG = "AlphabeticalAppsList";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_PREDICTIONS = false;
/**
* Info about a section in the alphabetic list
@@ -113,13 +135,6 @@ public class AlphabeticalAppsList {
}
/**
- * A filter interface to limit the set of applications in the apps list.
- */
- public interface Filter {
- boolean retainApp(AppInfo info, String sectionName);
- }
-
- /**
* Callback to notify when the set of adapter items have changed.
*/
public interface AdapterChangedCallback {
@@ -130,46 +145,63 @@ public class AlphabeticalAppsList {
* Common interface for different merging strategies.
*/
private interface MergeAlgorithm {
- boolean continueMerging(int sectionAppCount, int numAppsPerRow, int mergeCount);
+ boolean continueMerging(SectionInfo section, SectionInfo withSection,
+ int sectionAppCount, int numAppsPerRow, int mergeCount);
}
/**
- * The logic we use to merge sections on tablets.
+ * The logic we use to merge sections on tablets. Currently, we don't show section names on
+ * tablet layouts, so just merge all the sections indiscriminately.
*/
- private static class TabletMergeAlgorithm implements MergeAlgorithm {
+ @Thunk static class TabletMergeAlgorithm implements MergeAlgorithm {
@Override
- public boolean continueMerging(int sectionAppCount, int numAppsPerRow, int mergeCount) {
+ public boolean continueMerging(SectionInfo section, SectionInfo withSection,
+ int sectionAppCount, int numAppsPerRow, int mergeCount) {
// Merge EVERYTHING
return true;
}
}
/**
- * The logic we use to merge sections on phones.
+ * The logic we use to merge sections on phones. We only merge sections when their final row
+ * contains less than a certain number of icons, and stop at a specified max number of merges.
+ * In addition, we will try and not merge sections that identify apps from different scripts.
*/
private static class PhoneMergeAlgorithm implements MergeAlgorithm {
private int mMinAppsPerRow;
private int mMinRowsInMergedSection;
private int mMaxAllowableMerges;
+ private CharsetEncoder mAsciiEncoder;
public PhoneMergeAlgorithm(int minAppsPerRow, int minRowsInMergedSection, int maxNumMerges) {
mMinAppsPerRow = minAppsPerRow;
mMinRowsInMergedSection = minRowsInMergedSection;
mMaxAllowableMerges = maxNumMerges;
+ mAsciiEncoder = Charset.forName("US-ASCII").newEncoder();
}
@Override
- public boolean continueMerging(int sectionAppCount, int numAppsPerRow, int mergeCount) {
+ public boolean continueMerging(SectionInfo section, SectionInfo withSection,
+ int sectionAppCount, int numAppsPerRow, int mergeCount) {
// Continue merging if the number of hanging apps on the final row is less than some
// fixed number (ragged), the merged rows has yet to exceed some minimum row count,
// and while the number of merged sections is less than some fixed number of merges
int rows = sectionAppCount / numAppsPerRow;
int cols = sectionAppCount % numAppsPerRow;
+
+ // Ensure that we do not merge across scripts, currently we only allow for english and
+ // native scripts so we can test if both can just be ascii encoded
+ boolean isCrossScript = false;
+ if (section.firstAppItem != null && withSection.firstAppItem != null) {
+ isCrossScript = mAsciiEncoder.canEncode(section.firstAppItem.sectionName) !=
+ mAsciiEncoder.canEncode(withSection.firstAppItem.sectionName);
+ }
return (0 < cols && cols < mMinAppsPerRow) &&
rows < mMinRowsInMergedSection &&
- mergeCount < mMaxAllowableMerges;
+ mergeCount < mMaxAllowableMerges &&
+ !isCrossScript;
}
}
@@ -179,7 +211,7 @@ public class AlphabeticalAppsList {
private Launcher mLauncher;
// The set of apps from the system not including predictions
- private List<AppInfo> mApps = new ArrayList<>();
+ private final List<AppInfo> mApps = new ArrayList<>();
// The set of filtered apps with the current filter
private List<AppInfo> mFilteredApps = new ArrayList<>();
// The current set of adapter items
@@ -192,9 +224,10 @@ public class AlphabeticalAppsList {
private List<ComponentName> mPredictedAppComponents = new ArrayList<>();
// The set of predicted apps resolved from the component names and the current set of apps
private List<AppInfo> mPredictedApps = new ArrayList<>();
+ // The of ordered component names as a result of a search query
+ private ArrayList<ComponentName> mSearchResults;
private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>();
private RecyclerView.Adapter mAdapter;
- private Filter mFilter;
private AlphabeticIndexCompat mIndexer;
private AppNameComparator mAppNameComparator;
private MergeAlgorithm mMergeAlgorithm;
@@ -216,6 +249,10 @@ public class AlphabeticalAppsList {
mAdapterChangedCallback = cb;
}
+ public SimpleAppSearchManagerImpl newSimpleAppSearchManager() {
+ return new SimpleAppSearchManagerImpl(mApps);
+ }
+
/**
* Sets the number of apps per row. Used only for AppsContainerView.SECTIONED_GRID_COALESCED.
*/
@@ -274,22 +311,22 @@ public class AlphabeticalAppsList {
* Returns whether there are is a filter set.
*/
public boolean hasFilter() {
- return (mFilter != null);
+ return (mSearchResults != null);
}
/**
* Returns whether there are no filtered results.
*/
public boolean hasNoFilteredResults() {
- return (mFilter != null) && mFilteredApps.isEmpty();
+ return (mSearchResults != null) && mFilteredApps.isEmpty();
}
/**
- * Sets the current filter for this list of apps.
+ * Sets the sorted list of filtered components.
*/
- public void setFilter(Filter f) {
- if (mFilter != f) {
- mFilter = f;
+ public void setOrderedFilter(ArrayList<ComponentName> f) {
+ if (mSearchResults != f) {
+ mSearchResults = f;
updateAdapterItems();
}
}
@@ -409,7 +446,9 @@ public class AlphabeticalAppsList {
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
allApps.addAll(entry.getValue());
}
- mApps = allApps;
+
+ mApps.clear();
+ mApps.addAll(allApps);
} else {
// Just compute the section headers for use below
for (AppInfo info : mApps) {
@@ -439,6 +478,15 @@ public class AlphabeticalAppsList {
mAdapterItems.clear();
mSections.clear();
+ if (DEBUG_PREDICTIONS) {
+ if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
+ mPredictedAppComponents.add(mApps.get(0).componentName);
+ mPredictedAppComponents.add(mApps.get(0).componentName);
+ mPredictedAppComponents.add(mApps.get(0).componentName);
+ mPredictedAppComponents.add(mApps.get(0).componentName);
+ }
+ }
+
// Process the predicted app components
mPredictedApps.clear();
if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
@@ -464,16 +512,12 @@ public class AlphabeticalAppsList {
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
// ordered set of sections
- int numApps = mApps.size();
+ List<AppInfo> apps = getFiltersAppInfos();
+ int numApps = apps.size();
for (int i = 0; i < numApps; i++) {
- AppInfo info = mApps.get(i);
+ AppInfo info = apps.get(i);
String sectionName = getAndUpdateCachedSectionName(info.title);
- // Check if we want to retain this app
- if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
- continue;
- }
-
// Create a new section if the section names do not match
if (lastSectionInfo == null || !sectionName.equals(lastSectionName)) {
lastSectionName = sectionName;
@@ -514,6 +558,41 @@ public class AlphabeticalAppsList {
}
}
+ private List<AppInfo> getFiltersAppInfos() {
+ if (mSearchResults == null) {
+ return mApps;
+ }
+
+ int total = mSearchResults.size();
+ final HashMap<ComponentName, Integer> sortOrder = new HashMap<>(total);
+ for (int i = 0; i < total; i++) {
+ sortOrder.put(mSearchResults.get(i), i);
+ }
+
+ ArrayList<AppInfo> result = new ArrayList<>();
+ for (AppInfo info : mApps) {
+ if (sortOrder.containsKey(info.componentName)) {
+ result.add(info);
+ }
+ }
+
+ Collections.sort(result, new AbstractUserComparator<AppInfo>(
+ LauncherAppState.getInstance().getContext()) {
+
+ @Override
+ public int compare(AppInfo lhs, AppInfo rhs) {
+ Integer indexA = sortOrder.get(lhs.componentName);
+ int result = indexA.compareTo(sortOrder.get(rhs.componentName));
+ if (result == 0) {
+ return super.compare(lhs, rhs);
+ } else {
+ return result;
+ }
+ }
+ });
+ return result;
+ }
+
/**
* Merges multiple sections to reduce visual raggedness.
*/
@@ -521,14 +600,15 @@ public class AlphabeticalAppsList {
// Go through each section and try and merge some of the sections
if (AllAppsContainerView.GRID_MERGE_SECTIONS && !hasFilter()) {
int sectionAppCount = 0;
- for (int i = 0; i < mSections.size(); i++) {
+ for (int i = 0; i < mSections.size() - 1; i++) {
SectionInfo section = mSections.get(i);
sectionAppCount = section.numApps;
int mergeCount = 1;
// Merge rows based on the current strategy
- while (mMergeAlgorithm.continueMerging(sectionAppCount, mNumAppsPerRow, mergeCount) &&
- (i + 1) < mSections.size()) {
+ while (i < (mSections.size() - 1) &&
+ mMergeAlgorithm.continueMerging(section, mSections.get(i + 1),
+ sectionAppCount, mNumAppsPerRow, mergeCount)) {
SectionInfo nextSection = mSections.remove(i + 1);
// Remove the next section break
diff --git a/src/com/android/launcher3/allapps/AppSearchManager.java b/src/com/android/launcher3/allapps/AppSearchManager.java
new file mode 100644
index 000000000..b6aa22341
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AppSearchManager.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.ComponentName;
+
+import java.util.ArrayList;
+
+/**
+ * Interface for handling app search.
+ */
+public interface AppSearchManager {
+
+ /**
+ * Called when the search is about to be used. This method is optional for making a query but
+ * calling this appropriately can improve the initial response time.
+ */
+ void connect();
+
+ /**
+ * Cancels all pending search requests.
+ *
+ * @param interruptActiveRequests if true, any active requests which are already executing will
+ * be invalidated, and the corresponding results will not be sent. The client should usually
+ * set this to true, before beginning a new search session.
+ */
+ void cancel(boolean interruptActiveRequests);
+
+ /**
+ * Performs a search
+ */
+ void doSearch(String query, AppSearchResultCallback callback);
+
+ /**
+ * Callback for getting search results.
+ */
+ public interface AppSearchResultCallback {
+
+ /**
+ * Called when the search is complete.
+ *
+ * @param apps sorted list of matching components or null if in case of failure.
+ */
+ void onSearchResult(ArrayList<ComponentName> apps);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java b/src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java
new file mode 100644
index 000000000..e8a31b546
--- /dev/null
+++ b/src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.ComponentName;
+import android.os.Handler;
+
+import com.android.launcher3.AppInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * An {@link AppSearchManager} which does label matching on the UI thread.
+ */
+public class SimpleAppSearchManagerImpl implements AppSearchManager {
+
+ private static final Pattern SPLIT_PATTERN = Pattern.compile("[\\s|\\p{javaSpaceChar}]+");
+
+ private final List<AppInfo> mApps;
+ private final Handler mResultHandler;
+
+ public SimpleAppSearchManagerImpl(List<AppInfo> apps) {
+ mApps = apps;
+ mResultHandler = new Handler();
+ }
+
+ @Override
+ public void connect() {
+ // No op
+ }
+
+ @Override
+ public void cancel(boolean interruptActiveRequests) {
+ if (interruptActiveRequests) {
+ mResultHandler.removeCallbacksAndMessages(null);
+ }
+ }
+
+ @Override
+ public void doSearch(String query, final AppSearchResultCallback callback) {
+ // Do an intersection of the words in the query and each title, and filter out all the
+ // apps that don't match all of the words in the query.
+ final String queryTextLower = query.toLowerCase();
+ final String[] queryWords = SPLIT_PATTERN.split(queryTextLower);
+ final ArrayList<ComponentName> result = new ArrayList<ComponentName>();
+ int total = mApps.size();
+
+ for (int i = 0; i < total; i++) {
+ AppInfo info = mApps.get(i);
+ if (!result.contains(info.componentName) && matches(info, queryWords)) {
+ result.add(info.componentName);
+ }
+ }
+ mResultHandler.post(new Runnable() {
+
+ @Override
+ public void run() {
+ callback.onSearchResult(result);
+ }
+ });
+ }
+
+ private boolean matches(AppInfo info, String[] queryWords) {
+ String title = info.title.toString();
+ String[] words = SPLIT_PATTERN.split(title.toLowerCase());
+ for (int qi = 0; qi < queryWords.length; qi++) {
+ boolean foundMatch = false;
+ for (int i = 0; i < words.length; i++) {
+ if (words[i].startsWith(queryWords[qi])) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (!foundMatch) {
+ // If there is a word in the query that does not match any words in this
+ // title, so skip it.
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/com/android/launcher3/model/AbstractUserComparator.java b/src/com/android/launcher3/model/AbstractUserComparator.java
new file mode 100644
index 000000000..cf47ce648
--- /dev/null
+++ b/src/com/android/launcher3/model/AbstractUserComparator.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.content.Context;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
+import java.util.Comparator;
+import java.util.HashMap;
+
+/**
+ * A comparator to arrange items based on user profiles.
+ */
+public abstract class AbstractUserComparator<T extends ItemInfo> implements Comparator<T> {
+
+ private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
+ private final UserManagerCompat mUserManager;
+ private final UserHandleCompat mMyUser;
+
+ public AbstractUserComparator(Context context) {
+ mUserManager = UserManagerCompat.getInstance(context);
+ mMyUser = UserHandleCompat.myUserHandle();
+ }
+
+ @Override
+ public int compare(T lhs, T rhs) {
+ if (mMyUser.equals(lhs.user)) {
+ return -1;
+ } else {
+ Long aUserSerial = getAndCacheUserSerial(lhs.user);
+ Long bUserSerial = getAndCacheUserSerial(rhs.user);
+ return aUserSerial.compareTo(bUserSerial);
+ }
+ }
+
+ /**
+ * Returns the user serial for this user, using a cached serial if possible.
+ */
+ private Long getAndCacheUserSerial(UserHandleCompat user) {
+ Long userSerial = mUserSerialCache.get(user);
+ if (userSerial == null) {
+ userSerial = mUserManager.getSerialNumberForUser(user);
+ mUserSerialCache.put(user, userSerial);
+ }
+ return userSerial;
+ }
+
+ public void clearUserCache() {
+ mUserSerialCache.clear();
+ }
+}
diff --git a/src/com/android/launcher3/model/AppNameComparator.java b/src/com/android/launcher3/model/AppNameComparator.java
index 706f7515d..cd45d2c94 100644
--- a/src/com/android/launcher3/model/AppNameComparator.java
+++ b/src/com/android/launcher3/model/AppNameComparator.java
@@ -1,14 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.launcher3.model;
import android.content.Context;
import com.android.launcher3.AppInfo;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.compat.UserHandleCompat;
-import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.Thunk;
+
import java.text.Collator;
import java.util.Comparator;
-import java.util.HashMap;
/**
* Class to manage access to an app name comparator.
@@ -16,17 +30,15 @@ import java.util.HashMap;
* Used to sort application name in all apps view and widget tray view.
*/
public class AppNameComparator {
- private final UserManagerCompat mUserManager;
private final Collator mCollator;
- private final Comparator<ItemInfo> mAppInfoComparator;
+ private final AbstractUserComparator<ItemInfo> mAppInfoComparator;
private final Comparator<String> mSectionNameComparator;
- private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
public AppNameComparator(Context context) {
mCollator = Collator.getInstance();
- mUserManager = UserManagerCompat.getInstance(context);
- mAppInfoComparator = new Comparator<ItemInfo>() {
+ mAppInfoComparator = new AbstractUserComparator<ItemInfo>(context) {
+ @Override
public final int compare(ItemInfo a, ItemInfo b) {
// Order by the title in the current locale
int result = compareTitles(a.title.toString(), b.title.toString());
@@ -38,13 +50,7 @@ public class AppNameComparator {
if (result == 0) {
// If the two apps are the same component, then prioritize by the order that
// the app user was created (prioritizing the main user's apps)
- if (UserHandleCompat.myUserHandle().equals(a.user)) {
- return -1;
- } else {
- Long aUserSerial = getAndCacheUserSerial(a.user);
- Long bUserSerial = getAndCacheUserSerial(b.user);
- return aUserSerial.compareTo(bUserSerial);
- }
+ return super.compare(a, b);
}
}
return result;
@@ -63,7 +69,7 @@ public class AppNameComparator {
*/
public Comparator<ItemInfo> getAppInfoComparator() {
// Clear the user serial cache so that we get serials as needed in the comparator
- mUserSerialCache.clear();
+ mAppInfoComparator.clearUserCache();
return mAppInfoComparator;
}
@@ -77,7 +83,7 @@ public class AppNameComparator {
/**
* Compares two titles with the same return value semantics as Comparator.
*/
- private int compareTitles(String titleA, String titleB) {
+ @Thunk int compareTitles(String titleA, String titleB) {
// Ensure that we de-prioritize any titles that don't start with a linguistic letter or digit
boolean aStartsWithLetter = Character.isLetterOrDigit(titleA.codePointAt(0));
boolean bStartsWithLetter = Character.isLetterOrDigit(titleB.codePointAt(0));
@@ -90,16 +96,4 @@ public class AppNameComparator {
// Order by the title in the current locale
return mCollator.compare(titleA, titleB);
}
-
- /**
- * Returns the user serial for this user, using a cached serial if possible.
- */
- private Long getAndCacheUserSerial(UserHandleCompat user) {
- Long userSerial = mUserSerialCache.get(user);
- if (userSerial == null) {
- userSerial = mUserManager.getSerialNumberForUser(user);
- mUserSerialCache.put(user, userSerial);
- }
- return userSerial;
- }
}
diff --git a/src/com/android/launcher3/util/LongArrayMap.java b/src/com/android/launcher3/util/LongArrayMap.java
index e3c96cd42..a337e85bd 100644
--- a/src/com/android/launcher3/util/LongArrayMap.java
+++ b/src/com/android/launcher3/util/LongArrayMap.java
@@ -43,7 +43,7 @@ public class LongArrayMap<E> extends LongSparseArray<E> implements Iterable<E> {
return new ValueIterator();
}
- private class ValueIterator implements Iterator<E> {
+ @Thunk class ValueIterator implements Iterator<E> {
private int mNextIndex = 0;
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index d65455053..887587905 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -15,6 +15,7 @@ import com.android.launcher3.DragLayer;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.util.Thunk;
public class WidgetHostViewLoader {
@@ -38,7 +39,7 @@ public class WidgetHostViewLoader {
PendingAddWidgetInfo mCreateWidgetInfo = null;
// TODO: technically, this class should not have to know the existence of the launcher.
- private Launcher mLauncher;
+ @Thunk Launcher mLauncher;
private Handler mHandler;
public WidgetHostViewLoader(Launcher launcher) {
@@ -188,7 +189,7 @@ public class WidgetHostViewLoader {
return options;
}
- private void setState(int state) {
+ @Thunk void setState(int state) {
if (DEBUG) {
Log.d(TAG, String.format(" state [%d -> %d]", mState, state));
}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 11c2107f2..8d04be5e3 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -46,6 +46,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.Workspace;
import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.Thunk;
/**
* The widgets list view container.
@@ -60,7 +61,7 @@ public class WidgetsContainerView extends BaseContainerView
private static final int PRELOAD_SCREEN_HEIGHT_MULTIPLE = 1;
/* Global instances that are used inside this container. */
- private Launcher mLauncher;
+ @Thunk Launcher mLauncher;
private DragController mDragController;
private IconCache mIconCache;