diff options
Diffstat (limited to 'src/com')
38 files changed, 646 insertions, 709 deletions
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java index b75b3ef89..808bddbf3 100644 --- a/src/com/android/launcher3/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/AlphabeticalAppsList.java @@ -173,7 +173,7 @@ public class AlphabeticalAppsList { private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3; private static final int MAX_NUM_MERGES_PHONE = 2; - private Context mContext; + private Launcher mLauncher; // The set of apps from the system not including predictions private List<AppInfo> mApps = new ArrayList<>(); @@ -200,7 +200,7 @@ public class AlphabeticalAppsList { private int mNumPredictedAppsPerRow; public AlphabeticalAppsList(Context context, int numAppsPerRow, int numPredictedAppsPerRow) { - mContext = context; + mLauncher = (Launcher) context; mIndexer = new AlphabeticIndexCompat(context); mAppNameComparator = new AppNameComparator(context); setNumAppsPerRow(numAppsPerRow, numPredictedAppsPerRow); @@ -218,7 +218,7 @@ public class AlphabeticalAppsList { */ public void setNumAppsPerRow(int numAppsPerRow, int numPredictedAppsPerRow) { // Update the merge algorithm - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); if (grid.isPhone()) { mMergeAlgorithm = new PhoneMergeAlgorithm((int) Math.ceil(numAppsPerRow / 2f), MIN_ROWS_IN_MERGED_SECTION_PHONE, MAX_NUM_MERGES_PHONE); @@ -381,7 +381,7 @@ public class AlphabeticalAppsList { // As a special case for some languages (currently only Simplified Chinese), we may need to // coalesce sections - Locale curLocale = mContext.getResources().getConfiguration().locale; + Locale curLocale = mLauncher.getResources().getConfiguration().locale; TreeMap<String, ArrayList<AppInfo>> sectionMap = null; boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE); if (localeRequiresSectionSorting) { diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index e6bf52531..ea7c22189 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -75,8 +75,8 @@ public class AppWidgetResizeFrame extends FrameLayout { mResizeMode = info.resizeMode; mDragLayer = dragLayer; - mMinHSpan = info.minSpanX; - mMinVSpan = info.minSpanY; + mMinHSpan = info.getMinSpanX(mLauncher); + mMinVSpan = info.getMinSpanY(mLauncher); setBackgroundResource(R.drawable.widget_resize_shadow); setForeground(getResources().getDrawable(R.drawable.widget_resize_frame)); diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java index 31942b36d..109be7e02 100644 --- a/src/com/android/launcher3/AppsContainerRecyclerView.java +++ b/src/com/android/launcher3/AppsContainerRecyclerView.java @@ -80,6 +80,8 @@ public class AppsContainerRecyclerView extends BaseContainerRecyclerView { private Rect mBackgroundPadding = new Rect(); private ScrollPositionState mScrollPosState = new ScrollPositionState(); + private Launcher mLauncher; + public AppsContainerRecyclerView(Context context) { this(context, null); } @@ -96,6 +98,7 @@ public class AppsContainerRecyclerView extends BaseContainerRecyclerView { int defStyleRes) { super(context, attrs, defStyleAttr); + mLauncher = (Launcher) context; Resources res = context.getResources(); int fastScrollerSize = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_popup_size); mScrollbar = res.getDrawable(R.drawable.apps_list_scrollbar_thumb); @@ -129,7 +132,7 @@ public class AppsContainerRecyclerView extends BaseContainerRecyclerView { mNumAppsPerRow = numAppsPerRow; mNumPredictedAppsPerRow = numPredictedAppsPerRow; - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); RecyclerView.RecycledViewPool pool = getRecycledViewPool(); int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx); pool.setMaxRecycledViews(AppsGridAdapter.PREDICTION_BAR_SPACER_TYPE, 1); diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java index 26a7cd761..9ff3bfabc 100644 --- a/src/com/android/launcher3/AppsContainerView.java +++ b/src/com/android/launcher3/AppsContainerView.java @@ -199,15 +199,18 @@ public class AppsContainerView extends BaseContainerView implements DragSource, public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); Resources res = context.getResources(); + mLauncher = (Launcher) context; + DeviceProfile grid = mLauncher.getDeviceProfile(); + mContainerInset = context.getResources().getDimensionPixelSize( R.dimen.apps_container_inset); mPredictionBarHeight = grid.allAppsCellHeightPx + 2 * res.getDimensionPixelSize(R.dimen.apps_prediction_icon_top_bottom_padding); - mLauncher = (Launcher) context; + mLayoutInflater = LayoutInflater.from(context); + mNumAppsPerRow = grid.appsViewNumCols; mNumPredictedAppsPerRow = grid.appsViewNumPredictiveCols; mApps = new AlphabeticalAppsList(context, mNumAppsPerRow, mNumPredictedAppsPerRow); @@ -219,6 +222,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, mLayoutManager = mAdapter.getLayoutManager(); mItemDecoration = mAdapter.getItemDecoration(); mContentMarginStart = mAdapter.getContentMarginStart(); + mApps.setAdapter(mAdapter); } @@ -410,7 +414,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, protected void onFixedBoundsUpdated() { // Update the number of items in the grid LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); if (grid.updateAppsViewNumCols(getContext().getResources(), mFixedBounds.width())) { mNumAppsPerRow = grid.appsViewNumCols; mNumPredictedAppsPerRow = grid.appsViewNumPredictiveCols; @@ -448,7 +452,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, } // Update the apps recycler view, inset it by the container inset as well - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int startMargin = grid.isPhone() ? mContentMarginStart : 0; int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset; if (isRtl) { @@ -565,8 +569,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, @Override public float getIntrinsicIconScaleFactor() { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); return (float) grid.allAppsIconSizePx / grid.iconSizePx; } @@ -760,7 +763,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, */ private boolean handleTouchEvent(MotionEvent ev) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int x = (int) ev.getX(); int y = (int) ev.getY(); @@ -883,7 +886,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, */ private void showSearchField() { // Show the search bar and focus the search - final int translationX = DynamicGrid.pxFromDp(SEARCH_TRANSLATION_X_DP, + final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP, getContext().getResources().getDisplayMetrics()); mSearchBarContainerView.setVisibility(View.VISIBLE); mSearchBarContainerView.setAlpha(0f); @@ -913,7 +916,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource, */ private void hideSearchField(boolean animated, final boolean returnFocusToRecyclerView) { final boolean resetTextField = mSearchBarEditView.getText().toString().length() > 0; - final int translationX = DynamicGrid.pxFromDp(SEARCH_TRANSLATION_X_DP, + final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP, getContext().getResources().getDisplayMetrics()); if (animated) { // Hide the search bar and focus the recycler view diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java index 580930cf2..9c1c46b80 100644 --- a/src/com/android/launcher3/AppsGridAdapter.java +++ b/src/com/android/launcher3/AppsGridAdapter.java @@ -106,6 +106,11 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { private HashMap<String, PointF> mCachedSectionBounds = new HashMap<>(); private Rect mTmpBounds = new Rect(); + private Launcher mLauncher; + + public GridItemDecoration(Context context) { + mLauncher = (Launcher) context; + } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { @@ -113,7 +118,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { return; } - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); boolean hasDrawnPredictedAppsDivider = false; int childCount = parent.getChildCount(); @@ -294,7 +299,6 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { @Thunk Paint mSectionTextPaint; @Thunk Paint mPredictedAppsDividerPaint; - public AppsGridAdapter(Context context, AlphabeticalAppsList apps, int appsPerRow, PredictionBarSpacerCallbacks pbCb, View.OnTouchListener touchListener, View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) { @@ -307,7 +311,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { mGridLayoutMgr = new GridLayoutManager(context, appsPerRow, GridLayoutManager.VERTICAL, false); mGridLayoutMgr.setSpanSizeLookup(mGridSizer); - mItemDecoration = new GridItemDecoration(); + mItemDecoration = new GridItemDecoration(context); mLayoutInflater = LayoutInflater.from(context); mTouchListener = touchListener; mIconClickListener = iconClickListener; @@ -323,7 +327,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { mSectionTextPaint.setAntiAlias(true); mPredictedAppsDividerPaint = new Paint(); - mPredictedAppsDividerPaint.setStrokeWidth(DynamicGrid.pxFromDp(1f, res.getDisplayMetrics())); + mPredictedAppsDividerPaint.setStrokeWidth(Utilities.pxFromDp(1f, res.getDisplayMetrics())); mPredictedAppsDividerPaint.setColor(0x1E000000); mPredictedAppsDividerPaint.setAntiAlias(true); } diff --git a/src/com/android/launcher3/AppsRecyclerViewContainer.java b/src/com/android/launcher3/AppsRecyclerViewContainer.java index cf4beca28..6411bace4 100644 --- a/src/com/android/launcher3/AppsRecyclerViewContainer.java +++ b/src/com/android/launcher3/AppsRecyclerViewContainer.java @@ -38,8 +38,8 @@ public class AppsRecyclerViewContainer extends FrameLayout implements BubbleText public AppsRecyclerViewContainer(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + Launcher launcher = (Launcher) context; + DeviceProfile grid = launcher.getDeviceProfile(); mTouchFeedbackView = new ClickShadowView(context); diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index dac79a8ef..20c9314c9 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -78,7 +78,7 @@ public class AutoInstallsLayout { static AutoInstallsLayout get(Context context, String pkg, Resources targetRes, AppWidgetHost appWidgetHost, LayoutParserCallback callback) { - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + InvariantDeviceProfile grid = LauncherAppState.getInstance().getInvariantDeviceProfile(); // Try with grid size and hotseat count String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT, @@ -165,7 +165,7 @@ public class AutoInstallsLayout { LayoutParserCallback callback, Resources res, int layoutId, String rootTag) { this(context, appWidgetHost, callback, res, layoutId, rootTag, - LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile().hotseatAllAppsRank); + LauncherAppState.getInstance().getInvariantDeviceProfile().hotseatAllAppsRank); } public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost, diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index d5300095b..edf502112 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -93,7 +93,7 @@ public class BubbleTextView extends TextView { public BubbleTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = ((Launcher) context).getDeviceProfile(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BubbleTextView, defStyle, 0); diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 1d211bff1..27f1ac611 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -199,8 +199,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { setClipToPadding(false); mLauncher = (Launcher) context; - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); mCellWidth = mCellHeight = -1; @@ -208,8 +207,8 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { mWidthGap = mOriginalWidthGap = 0; mHeightGap = mOriginalHeightGap = 0; mMaxGap = Integer.MAX_VALUE; - mCountX = (int) grid.numColumns; - mCountY = (int) grid.numRows; + mCountX = (int) grid.inv.numColumns; + mCountY = (int) grid.inv.numRows; mOccupied = new boolean[mCountX][mCountY]; mTmpOccupied = new boolean[mCountX][mCountY]; mPreviousReorderDirection[0] = INVALID_DIRECTION; @@ -499,8 +498,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { int previewOffset = FolderRingAnimator.sPreviewSize; // The folder outer / inner ring image(s) - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); for (int i = 0; i < mFolderOuterRings.size(); i++) { FolderRingAnimator fra = mFolderOuterRings.get(i); @@ -841,8 +839,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); @@ -2729,18 +2726,18 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { * @param height Height in pixels * @param result An array of length 2 in which to store the result (may be null). */ - public static int[] rectToCell(int width, int height, int[] result) { + public static int[] rectToCell(Launcher launcher, int width, int height, int[] result) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = launcher.getDeviceProfile(); Rect padding = grid.getWorkspacePadding(grid.isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT); // Always assume we're working with the smallest span to make sure we // reserve enough space in both orientations. int parentWidth = grid.calculateCellWidth(grid.widthPx - - padding.left - padding.right, (int) grid.numColumns); + - padding.left - padding.right, (int) grid.inv.numColumns); int parentHeight = grid.calculateCellHeight(grid.heightPx - - padding.top - padding.bottom, (int) grid.numRows); + - padding.top - padding.bottom, (int) grid.inv.numRows); int smallerSize = Math.min(parentWidth, parentHeight); // Always round up to next largest cell @@ -2773,7 +2770,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { info.spanX = info.spanY = 1; return; } - int[] spans = rectToCell(minWidth, minHeight, null); + int[] spans = rectToCell(mLauncher, minWidth, minHeight, null); info.spanX = spans[0]; info.spanY = spans[1]; } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index ad0afd97b..8ab58b9c0 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -27,6 +27,7 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.util.DisplayMetrics; +import android.util.TypedValue; import android.view.Display; import android.view.Gravity; import android.view.Surface; @@ -44,42 +45,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; - -class DeviceProfileQuery { - DeviceProfile profile; - float widthDps; - float heightDps; - float value; - PointF dimens; - - DeviceProfileQuery(DeviceProfile p, float v) { - widthDps = p.minWidthDps; - heightDps = p.minHeightDps; - value = v; - dimens = new PointF(widthDps, heightDps); - profile = p; - } -} - public class DeviceProfile { + public static interface DeviceProfileCallbacks { public void onAvailableSizeChanged(DeviceProfile grid); } - String name; - float minWidthDps; - float minHeightDps; - public int numRows; - public int numColumns; - public int numFolderRows; - public int numFolderColumns; - float numHotseatIcons; - float iconSize; - private float iconTextSize; + public final InvariantDeviceProfile inv; private int iconDrawablePaddingOriginalPx; - private float hotseatIconSize; - - int defaultLayoutId; boolean isLandscape; public boolean isTablet; @@ -107,11 +80,7 @@ public class DeviceProfile { public int cellWidthPx; public int cellHeightPx; - public int iconSizePx; - public int iconTextSizePx; int iconDrawablePaddingPx; - int allAppsIconSizePx; - int allAppsIconTextSizePx; int allAppsCellWidthPx; int allAppsCellHeightPx; int allAppsCellPaddingPx; @@ -123,7 +92,6 @@ public class DeviceProfile { int hotseatCellHeightPx; int hotseatIconSizePx; int hotseatBarHeightPx; - int hotseatAllAppsRank; int allAppsNumRows; int allAppsNumCols; int appsViewNumCols; @@ -133,6 +101,11 @@ public class DeviceProfile { int pageIndicatorHeightPx; int allAppsButtonVisualSize; + int iconSizePx; + public int iconTextSizePx; + int allAppsIconSizePx; + int allAppsIconTextSizePx; + float dragViewScale; int allAppsShortEdgeCount = -1; @@ -140,46 +113,26 @@ public class DeviceProfile { private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>(); - DeviceProfile(String n, float w, float h, - int r, int c, int fr, int fc, - float is, float its, float hs, float his, int dlId) { - // Ensure that we have an odd number of hotseat items (since we need to place all apps) - if (hs % 2 == 0) { - throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces"); - } - - name = n; - minWidthDps = w; - minHeightDps = h; + public DeviceProfile(Context context, InvariantDeviceProfile inv) { + // Determine the dynamic grid properties + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); - numRows = r; - numColumns = c; - numFolderRows = fr; - numFolderColumns = fc; + Point realSize = new Point(); + display.getRealSize(realSize); + DisplayMetrics dm = new DisplayMetrics(); + display.getMetrics(dm); - iconSize = is; - iconTextSize = its; - numHotseatIcons = hs; - hotseatIconSize = his; - defaultLayoutId = dlId; + this.inv = inv; + init(context, realSize.x, realSize.y, dm.widthPixels, dm.heightPixels); } - DeviceProfile() { - } - - DeviceProfile(Context context, - ArrayList<DeviceProfile> profiles, - float minWidth, float minHeight, - int wPx, int hPx, - int awPx, int ahPx, - Resources res) { + private void init(Context context, int wPx, int hPx, int awPx, int ahPx) { + Resources res = context.getResources(); DisplayMetrics dm = res.getDisplayMetrics(); - ArrayList<DeviceProfileQuery> points = - new ArrayList<DeviceProfileQuery>(); + transposeLayoutWithOrientation = res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation); - minWidthDps = minWidth; - minHeightDps = minHeight; ComponentName cn = new ComponentName(context.getPackageName(), this.getClass().getName()); @@ -205,56 +158,14 @@ public class DeviceProfile { overviewModeScaleFactor = res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f; - // Find the closes profile given the width/height - for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p, 0f)); - } - DeviceProfile closestProfile = findClosestDeviceProfile(minWidth, minHeight, points); - - // Snap to the closest row count - numRows = closestProfile.numRows; - - // Snap to the closest column count - numColumns = closestProfile.numColumns; - - numFolderRows = closestProfile.numFolderRows; - numFolderColumns = closestProfile.numFolderColumns; - - // Snap to the closest hotseat size - numHotseatIcons = closestProfile.numHotseatIcons; - hotseatAllAppsRank = (int) (numHotseatIcons / 2); - - // Snap to the closest default layout id - defaultLayoutId = closestProfile.defaultLayoutId; - - // Interpolate the icon size - points.clear(); - for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p, p.iconSize)); - } - iconSize = invDistWeightedInterpolate(minWidth, minHeight, points); - - // AllApps uses the original non-scaled icon size - allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm); - - // Interpolate the icon text size - points.clear(); - for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p, p.iconTextSize)); - } - iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points); iconDrawablePaddingOriginalPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding); + // AllApps uses the original non-scaled icon text size - allAppsIconTextSizePx = DynamicGrid.pxFromDp(iconTextSize, dm); + allAppsIconTextSizePx = Utilities.pxFromDp(inv.iconTextSize, dm); - // Interpolate the hotseat icon size - points.clear(); - for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p, p.hotseatIconSize)); - } - // Hotseat - hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points); + // AllApps uses the original non-scaled icon size + allAppsIconSizePx = Utilities.pxFromDp(inv.iconSize, dm); // If the partner customization apk contains any grid overrides, apply them applyPartnerDeviceProfileOverrides(context, dm); @@ -273,22 +184,7 @@ public class DeviceProfile { private void applyPartnerDeviceProfileOverrides(Context ctx, DisplayMetrics dm) { Partner p = Partner.get(ctx.getPackageManager()); if (p != null) { - DeviceProfile partnerDp = p.getDeviceProfileOverride(dm); - if (partnerDp != null) { - if (partnerDp.numRows > 0 && partnerDp.numColumns > 0) { - numRows = numFolderRows = partnerDp.numRows; - numColumns = numFolderColumns = partnerDp.numColumns; - } - if (partnerDp.allAppsShortEdgeCount > 0 && partnerDp.allAppsLongEdgeCount > 0) { - allAppsShortEdgeCount = partnerDp.allAppsShortEdgeCount; - allAppsLongEdgeCount = partnerDp.allAppsLongEdgeCount; - } - if (partnerDp.iconSize > 0) { - iconSize = partnerDp.iconSize; - // AllApps uses the original non-scaled icon size - allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm); - } - } + p.applyDeviceProfileOverrides(this); } } @@ -361,7 +257,7 @@ public class DeviceProfile { float scale = 1f; int drawablePadding = iconDrawablePaddingOriginalPx; updateIconSize(1f, drawablePadding, resources, dm); - float usedHeight = (cellHeightPx * numRows); + float usedHeight = (cellHeightPx * inv.numRows); Rect workspacePadding = getWorkspacePadding(); int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom); @@ -379,10 +275,10 @@ public class DeviceProfile { private void updateIconSize(float scale, int drawablePadding, Resources res, DisplayMetrics dm) { - iconSizePx = (int) (DynamicGrid.pxFromDp(iconSize, dm) * scale); - iconTextSizePx = (int) (DynamicGrid.pxFromSp(iconTextSize, dm) * scale); + iconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale); + iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale); iconDrawablePaddingPx = drawablePadding; - hotseatIconSizePx = (int) (DynamicGrid.pxFromDp(hotseatIconSize, dm) * scale); + hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale); // Search Bar searchBarSpaceWidthPx = Math.min(widthPx, @@ -468,74 +364,6 @@ public class DeviceProfile { updateAvailableDimensions(context); } - @Thunk float dist(PointF p0, PointF p1) { - return (float) Math.hypot(p1.x - p0.x, p1.y - p0.y); - } - - private float weight(PointF a, PointF b, - float pow) { - float d = dist(a, b); - if (d == 0f) { - return Float.POSITIVE_INFINITY; - } - return (float) (1f / Math.pow(d, pow)); - } - - /** Returns the closest device profile given the width and height and a list of profiles */ - private DeviceProfile findClosestDeviceProfile(float width, float height, - ArrayList<DeviceProfileQuery> points) { - return findClosestDeviceProfiles(width, height, points).get(0).profile; - } - - /** Returns the closest device profiles ordered by closeness to the specified width and height */ - private ArrayList<DeviceProfileQuery> findClosestDeviceProfiles(float width, float height, - ArrayList<DeviceProfileQuery> points) { - final PointF xy = new PointF(width, height); - - // Sort the profiles by their closeness to the dimensions - ArrayList<DeviceProfileQuery> pointsByNearness = points; - Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() { - public int compare(DeviceProfileQuery a, DeviceProfileQuery b) { - return (int) (dist(xy, a.dimens) - dist(xy, b.dimens)); - } - }); - - return pointsByNearness; - } - - private float invDistWeightedInterpolate(float width, float height, - ArrayList<DeviceProfileQuery> points) { - float sum = 0; - float weights = 0; - float pow = 5; - float kNearestNeighbors = 3; - final PointF xy = new PointF(width, height); - - ArrayList<DeviceProfileQuery> pointsByNearness = findClosestDeviceProfiles(width, height, - points); - - for (int i = 0; i < pointsByNearness.size(); ++i) { - DeviceProfileQuery p = pointsByNearness.get(i); - if (i < kNearestNeighbors) { - float w = weight(xy, p.dimens, pow); - if (w == Float.POSITIVE_INFINITY) { - return p.value; - } - weights += w; - } - } - - for (int i = 0; i < pointsByNearness.size(); ++i) { - DeviceProfileQuery p = pointsByNearness.get(i); - if (i < kNearestNeighbors) { - float w = weight(xy, p.dimens, pow); - sum += w * p.value / weights; - } - } - - return sum; - } - /** Returns the search bar top offset */ int getSearchBarTopOffset() { if (isTablet() && !isVerticalBarLayout()) { @@ -571,7 +399,7 @@ public class DeviceProfile { // XXX: If the icon size changes across orientations, we will have to take // that into account here too. int gap = (int) ((width - 2 * edgeMarginPx - - (numColumns * cellWidthPx)) / (2 * (numColumns + 1))); + (inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1))); bounds.set(edgeMarginPx + gap, getSearchBarTopOffset(), availableWidthPx - (edgeMarginPx + gap), searchBarSpaceHeightPx); @@ -620,6 +448,7 @@ public class DeviceProfile { Rect getWorkspacePadding() { return getWorkspacePadding(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT); } + Rect getWorkspacePadding(int orientation) { Rect searchBarBounds = getSearchBarBounds(orientation); Rect padding = new Rect(); @@ -646,10 +475,10 @@ public class DeviceProfile { : Math.min(widthPx, heightPx); int paddingTop = searchBarBounds.bottom; int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx; - int availableWidth = Math.max(0, width - (int) ((numColumns * cellWidthPx) + - (numColumns * gapScale * cellWidthPx))); + int availableWidth = Math.max(0, width - (int) ((inv.numColumns * cellWidthPx) + + (inv.numColumns * gapScale * cellWidthPx))); int availableHeight = Math.max(0, height - paddingTop - paddingBottom - - (int) (2 * numRows * cellHeightPx)); + - (int) (2 * inv.numRows * cellHeightPx)); padding.set(availableWidth / 2, paddingTop + availableHeight / 2, availableWidth / 2, paddingBottom + availableHeight / 2); } else { @@ -701,10 +530,10 @@ public class DeviceProfile { } } - int calculateCellWidth(int width, int countX) { + public static int calculateCellWidth(int width, int countX) { return width / countX; } - int calculateCellHeight(int height, int countY) { + public static int calculateCellHeight(int height, int countY) { return height / countY; } diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java deleted file mode 100644 index d22427f44..000000000 --- a/src/com/android/launcher3/DynamicGrid.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3; - -import android.content.Context; -import android.content.res.Resources; -import android.util.DisplayMetrics; -import android.util.TypedValue; - -import java.util.ArrayList; - - -public class DynamicGrid { - @SuppressWarnings("unused") - private static final String TAG = "DynamicGrid"; - - private DeviceProfile mProfile; - private float mMinWidth; - private float mMinHeight; - - // This is a static that we use for the default icon size on a 4/5-inch phone - static float DEFAULT_ICON_SIZE_DP = 60; - static float DEFAULT_ICON_SIZE_PX = 0; - - public static float dpiFromPx(int size, DisplayMetrics metrics){ - float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT; - return (size / densityRatio); - } - public static int pxFromDp(float size, DisplayMetrics metrics) { - return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - size, metrics)); - } - public static int pxFromSp(float size, DisplayMetrics metrics) { - return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, - size, metrics)); - } - - public DynamicGrid(Context context, Resources resources, - int minWidthPx, int minHeightPx, - int widthPx, int heightPx, - int awPx, int ahPx) { - DisplayMetrics dm = resources.getDisplayMetrics(); - ArrayList<DeviceProfile> deviceProfiles = - new ArrayList<DeviceProfile>(); - DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm); - // Our phone profiles include the bar sizes in each orientation - deviceProfiles.add(new DeviceProfile("Super Short Stubby", - 255, 300, 2, 3, 2, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Shorter Stubby", - 255, 400, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Short Stubby", - 275, 420, 3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Stubby", - 255, 450, 3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Nexus S", - 296, 491.33f, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Nexus 4", - 335, 567, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Nexus 5", - 359, 567, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4)); - deviceProfiles.add(new DeviceProfile("Large Phone", - 406, 694, 5, 5, 4, 4, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5)); - // The tablet profile is odd in that the landscape orientation - // also includes the nav bar on the side - deviceProfiles.add(new DeviceProfile("Nexus 7", - 575, 904, 5, 6, 4, 5, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6)); - // Larger tablet profiles always have system bars on the top & bottom - deviceProfiles.add(new DeviceProfile("Nexus 10", - 727, 1207, 5, 6, 4, 5, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6)); - deviceProfiles.add(new DeviceProfile("20-inch Tablet", - 1527, 2527, 7, 7, 6, 6, 100, 20, 7, 72, R.xml.default_workspace_4x4)); - mMinWidth = dpiFromPx(minWidthPx, dm); - mMinHeight = dpiFromPx(minHeightPx, dm); - mProfile = new DeviceProfile(context, deviceProfiles, - mMinWidth, mMinHeight, - widthPx, heightPx, - awPx, ahPx, - resources); - } - - public DeviceProfile getDeviceProfile() { - return mProfile; - } - - public String toString() { - return "-------- DYNAMIC GRID ------- \n" + - "Wd: " + mProfile.minWidthDps + ", Hd: " + mProfile.minHeightDps + - ", W: " + mProfile.widthPx + ", H: " + mProfile.heightPx + - " [r: " + mProfile.numRows + ", c: " + mProfile.numColumns + - ", is: " + mProfile.iconSizePx + ", its: " + mProfile.iconTextSizePx + - ", cw: " + mProfile.cellWidthPx + ", ch: " + mProfile.cellHeightPx + - ", hc: " + mProfile.numHotseatIcons + ", his: " + mProfile.hotseatIconSizePx + "]"; - } -} diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 678ed0f82..fe50e3a4e 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -92,11 +92,13 @@ public class FocusHelper { final int pageIndex = pagedView.indexOfChild(cellLayout); final int pageCount = pagedView.getPageCount(); + Launcher launcher = (Launcher) v.getContext(); int[][] matrix = FocusLogic.createSparseMatrix(cellLayout); // Process focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, + countY, matrix, iconIndex, pageIndex, pageCount, + launcher.getDeviceProfile().isLayoutRtl); if (newIconIndex == FocusLogic.NOOP) { handleNoopKey(keyCode, v); return consume; @@ -184,7 +186,8 @@ public class FocusHelper { return consume; } - DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile profile = ((Launcher) v.getContext()).getDeviceProfile(); + if (DEBUG) { Log.v(TAG, String.format( "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s", @@ -248,8 +251,8 @@ public class FocusHelper { } // Process the focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, + countY, matrix, iconIndex, pageIndex, pageCount, profile.isLayoutRtl); View newIcon = null; if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) { @@ -283,8 +286,8 @@ public class FocusHelper { return consume; } - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile profile = app.getDynamicGrid().getDeviceProfile(); + Launcher launcher = (Launcher) v.getContext(); + DeviceProfile profile = launcher.getDeviceProfile(); if (DEBUG) { Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] isVerticalBar=%s", @@ -295,9 +298,9 @@ public class FocusHelper { ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); CellLayout iconLayout = (CellLayout) parent.getParent(); final Workspace workspace = (Workspace) iconLayout.getParent(); - final ViewGroup launcher = (ViewGroup) workspace.getParent(); - final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar); - final Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat); + final ViewGroup dragLayer = (ViewGroup) workspace.getParent(); + final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.search_drop_target_bar); + final Hotseat hotseat = (Hotseat) dragLayer.findViewById(R.id.hotseat); final int iconIndex = parent.indexOfChild(v); final int pageIndex = workspace.indexOfChild(iconLayout); @@ -331,8 +334,8 @@ public class FocusHelper { } // Process the focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, + countY, matrix, iconIndex, pageIndex, pageCount, profile.isLayoutRtl); View newIcon = null; switch (newIconIndex) { case FocusLogic.NOOP: @@ -354,8 +357,8 @@ public class FocusHelper { iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, iconLayout.getCountX(), row); - newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, - FocusLogic.PIVOT, newPageIndex, pageCount); + newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, + matrix, FocusLogic.PIVOT, newPageIndex, pageCount, profile.isLayoutRtl); newIcon = parent.getChildAt(newIconIndex); } break; @@ -387,8 +390,8 @@ public class FocusHelper { workspace.snapToPage(newPageIndex); iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row); - newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, - FocusLogic.PIVOT, newPageIndex, pageCount); + newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, + matrix, FocusLogic.PIVOT, newPageIndex, pageCount, profile.isLayoutRtl); newIcon = parent.getChildAt(newIconIndex); } break; diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index d0a7ba3f8..72dc1e94a 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -945,8 +945,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, sTempRect); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int centerX = (int) (sTempRect.left + sTempRect.width() * scale / 2); int centerY = (int) (sTempRect.top + sTempRect.height() * scale / 2); @@ -1003,8 +1002,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } private int getContentAreaHeight() { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); Rect workspacePadding = grid.getWorkspacePadding(grid.isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT); int maxContentAreaHeight = grid.availableHeightPx - diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java index b161b1cd3..8652eef40 100644 --- a/src/com/android/launcher3/FolderIcon.java +++ b/src/com/android/launcher3/FolderIcon.java @@ -147,8 +147,8 @@ public class FolderIcon extends FrameLayout implements FolderListener { "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " + "is dependent on this"); } - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + + DeviceProfile grid = launcher.getDeviceProfile(); FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false); icon.setClipToPadding(false); @@ -217,8 +217,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { + Thread.currentThread()); } - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = launcher.getDeviceProfile(); sPreviewSize = grid.folderIconSizePx; sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding); sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo); @@ -490,8 +489,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { private void computePreviewDrawingParams(int drawableSize, int totalSize) { if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); mIntrinsicIconSize = drawableSize; mTotalWidth = totalSize; diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java index 06ed58895..0bd6501ed 100644 --- a/src/com/android/launcher3/FolderPagedView.java +++ b/src/com/android/launcher3/FolderPagedView.java @@ -80,9 +80,9 @@ public class FolderPagedView extends PagedView { super(context, attrs); LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - mMaxCountX = (int) grid.numFolderColumns; - mMaxCountY = (int) grid.numFolderRows; + InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); + mMaxCountX = (int) profile.numFolderColumns; + mMaxCountY = (int) profile.numFolderRows; mMaxItemsPerPage = mMaxCountX * mMaxCountY; @@ -229,7 +229,7 @@ public class FolderPagedView extends PagedView { } private CellLayout createAndAddNewPage() { - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = ((Launcher) getContext()).getDeviceProfile(); CellLayout page = new CellLayout(getContext()); page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx); page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false); diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index b8337b6a4..1c1342cfe 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -54,10 +54,7 @@ public class Hotseat extends FrameLayout { r.getBoolean(R.bool.hotseat_transpose_layout_with_orientation); mIsLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - } - - public void setup(Launcher launcher) { - mLauncher = launcher; + mLauncher = (Launcher) context; } CellLayout getLayout() { @@ -108,15 +105,14 @@ public class Hotseat extends FrameLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); - mAllAppsButtonRank = grid.hotseatAllAppsRank; + mAllAppsButtonRank = grid.inv.hotseatAllAppsRank; mContent = (CellLayout) findViewById(R.id.layout); if (grid.isLandscape && !grid.isLargeTablet()) { - mContent.setGridSize(1, (int) grid.numHotseatIcons); + mContent.setGridSize(1, (int) grid.inv.numHotseatIcons); } else { - mContent.setGridSize((int) grid.numHotseatIcons, 1); + mContent.setGridSize((int) grid.inv.numHotseatIcons, 1); } mContent.setIsHotseat(true); diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 8b5f747f2..0c91a7113 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -94,7 +94,7 @@ public class IconCache { private final Handler mWorkerHandler; - public IconCache(Context context) { + public IconCache(Context context, InvariantDeviceProfile inv) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); @@ -374,20 +374,6 @@ public class IconCache { } /** - * Empty out the cache that aren't of the correct grid size - */ - public synchronized void flushInvalidIcons(DeviceProfile grid) { - Iterator<Entry<ComponentKey, CacheEntry>> it = mCache.entrySet().iterator(); - while (it.hasNext()) { - final CacheEntry e = it.next().getValue(); - if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx - || e.icon.getHeight() < grid.iconSizePx)) { - it.remove(); - } - } - } - - /** * Fetches high-res icon for the provided ItemInfo and updates the caller when done. * @return a request ID that can be used to cancel the request. */ diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java new file mode 100644 index 000000000..fcd6d60f6 --- /dev/null +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -0,0 +1,264 @@ +/* + * 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.content.Context; +import android.graphics.Point; +import android.graphics.PointF; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Display; +import android.view.WindowManager; + +import com.android.launcher3.util.Thunk; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class InvariantDeviceProfile { + private static final String TAG = "InvariantDeviceProfile"; + + // This is a static that we use for the default icon size on a 4/5-inch phone + static float DEFAULT_ICON_SIZE_DP = 60; + + + static ArrayList<InvariantDeviceProfile> sDeviceProfiles = + new ArrayList<InvariantDeviceProfile>(); + static { + sDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby", + 255, 300, 2, 3, 2, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby", + 255, 400, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby", + 275, 420, 3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Stubby", + 255, 450, 3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Nexus S", + 296, 491.33f, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4", + 335, 567, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5", + 359, 567, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4)); + sDeviceProfiles.add(new InvariantDeviceProfile("Large Phone", + 406, 694, 5, 5, 4, 4, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5)); + // The tablet profile is odd in that the landscape orientation + // also includes the nav bar on the side + sDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7", + 575, 904, 5, 6, 4, 5, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6)); + // Larger tablet profiles always have system bars on the top & bottom + sDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10", + 727, 1207, 5, 6, 4, 5, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6)); + sDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet", + 1527, 2527, 7, 7, 6, 6, 100, 20, 7, 72, R.xml.default_workspace_4x4)); + } + + class DeviceProfileQuery { + InvariantDeviceProfile profile; + float widthDps; + float heightDps; + float value; + PointF dimens; + + DeviceProfileQuery(InvariantDeviceProfile p, float v) { + widthDps = p.minWidthDps; + heightDps = p.minHeightDps; + value = v; + dimens = new PointF(widthDps, heightDps); + profile = p; + } + } + + // Profile-defining invariant properties + String name; + float minWidthDps; + float minHeightDps; + public int numRows; + public int numColumns; + public int numFolderRows; + public int numFolderColumns; + float iconSize; + float iconTextSize; + float numHotseatIcons; + float hotseatIconSize; + int defaultLayoutId; + + // Derived invariant properties + int hotseatAllAppsRank; + + InvariantDeviceProfile() { + } + + InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, + float is, float its, float hs, float his, int dlId) { + // Ensure that we have an odd number of hotseat items (since we need to place all apps) + if (hs % 2 == 0) { + throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces"); + } + + name = n; + minWidthDps = w; + minHeightDps = h; + numRows = r; + numColumns = c; + numFolderRows = fr; + numFolderColumns = fc; + iconSize = is; + iconTextSize = its; + numHotseatIcons = hs; + hotseatIconSize = his; + defaultLayoutId = dlId; + } + + InvariantDeviceProfile(Context context) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + DisplayMetrics dm = new DisplayMetrics(); + display.getMetrics(dm); + + Point smallestSize = new Point(); + Point largestSize = new Point(); + display.getCurrentSizeRange(smallestSize, largestSize); + + minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm); + minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm); + + ArrayList<DeviceProfileQuery> points = + new ArrayList<DeviceProfileQuery>(); + + // Find the closes profile given the width/height + for (InvariantDeviceProfile p : sDeviceProfiles) { + points.add(new DeviceProfileQuery(p, 0f)); + } + + InvariantDeviceProfile closestProfile = + findClosestDeviceProfile(minWidthDps, minHeightDps, points); + + // The following properties are inherited directly from the nearest archetypal profile + numRows = closestProfile.numRows; + numColumns = closestProfile.numColumns; + numHotseatIcons = closestProfile.numHotseatIcons; + hotseatAllAppsRank = (int) (numHotseatIcons / 2); + defaultLayoutId = closestProfile.defaultLayoutId; + numFolderRows = closestProfile.numFolderRows; + numFolderColumns = closestProfile.numFolderColumns; + + + // The following properties are interpolated based on proximity to nearby archetypal + // profiles + points.clear(); + for (InvariantDeviceProfile p : sDeviceProfiles) { + points.add(new DeviceProfileQuery(p, p.iconSize)); + } + iconSize = invDistWeightedInterpolate(minWidthDps, minHeightDps, points); + points.clear(); + for (InvariantDeviceProfile p : sDeviceProfiles) { + points.add(new DeviceProfileQuery(p, p.iconTextSize)); + } + iconTextSize = invDistWeightedInterpolate(minWidthDps, minHeightDps, points); + points.clear(); + for (InvariantDeviceProfile p : sDeviceProfiles) { + points.add(new DeviceProfileQuery(p, p.hotseatIconSize)); + } + hotseatIconSize = invDistWeightedInterpolate(minWidthDps, minHeightDps, points); + + // If the partner customization apk contains any grid overrides, apply them + // Supported overrides: numRows, numColumns, iconSize + applyPartnerDeviceProfileOverrides(context, dm); + } + + /** + * Apply any Partner customization grid overrides. + * + * Currently we support: all apps row / column count. + */ + private void applyPartnerDeviceProfileOverrides(Context ctx, DisplayMetrics dm) { + Partner p = Partner.get(ctx.getPackageManager()); + if (p != null) { + p.applyInvariantDeviceProfileOverrides(this, dm); + } + } + + @Thunk float dist(PointF p0, PointF p1) { + return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) + + (p1.y-p0.y)*(p1.y-p0.y)); + } + + private float weight(PointF a, PointF b, + float pow) { + float d = dist(a, b); + if (d == 0f) { + return Float.POSITIVE_INFINITY; + } + return (float) (1f / Math.pow(d, pow)); + } + + /** Returns the closest device profile given the width and height and a list of profiles */ + private InvariantDeviceProfile findClosestDeviceProfile(float width, float height, + ArrayList<DeviceProfileQuery> points) { + return findClosestDeviceProfiles(width, height, points).get(0).profile; + } + + /** Returns the closest device profiles ordered by closeness to the specified width and height */ + private ArrayList<DeviceProfileQuery> findClosestDeviceProfiles(float width, float height, + ArrayList<DeviceProfileQuery> points) { + final PointF xy = new PointF(width, height); + + // Sort the profiles by their closeness to the dimensions + ArrayList<DeviceProfileQuery> pointsByNearness = points; + Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() { + public int compare(DeviceProfileQuery a, DeviceProfileQuery b) { + return (int) (dist(xy, a.dimens) - dist(xy, b.dimens)); + } + }); + + return pointsByNearness; + } + + private float invDistWeightedInterpolate(float width, float height, + ArrayList<DeviceProfileQuery> points) { + float sum = 0; + float weights = 0; + float pow = 5; + float kNearestNeighbors = 3; + final PointF xy = new PointF(width, height); + + ArrayList<DeviceProfileQuery> pointsByNearness = findClosestDeviceProfiles(width, height, + points); + + for (int i = 0; i < pointsByNearness.size(); ++i) { + DeviceProfileQuery p = pointsByNearness.get(i); + if (i < kNearestNeighbors) { + float w = weight(xy, p.dimens, pow); + if (w == Float.POSITIVE_INFINITY) { + return p.value; + } + weights += w; + } + } + + for (int i = 0; i < pointsByNearness.size(); ++i) { + DeviceProfileQuery p = pointsByNearness.get(i); + if (i < kNearestNeighbors) { + float w = weight(xy, p.dimens, pow); + sum += w * p.value / weights; + } + } + + return sum; + } +} diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index a305d101d..6c7373907 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -430,8 +430,9 @@ public class Launcher extends Activity LauncherAppState app = LauncherAppState.getInstance(); LauncherAppState.getLauncherProvider().setLauncherProviderChangeListener(this); - // Lazy-initialize the dynamic grid - mDeviceProfile = app.initDynamicGrid(this); + // Load configuration-specific DeviceProfile + mDeviceProfile = new DeviceProfile(this, app.getInvariantDeviceProfile()); + mDeviceProfile.addCallback(LauncherAppState.getInstance()); // the LauncherApplication should call this, but in case of Instrumentation it might not be present yet mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(), @@ -439,7 +440,7 @@ public class Launcher extends Activity mIsSafeModeEnabled = getPackageManager().isSafeMode(); mModel = app.setLauncher(this); mIconCache = app.getIconCache(); - mIconCache.flushInvalidIcons(mDeviceProfile); + mDragController = new DragController(this); mInflater = getLayoutInflater(); mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, this); @@ -1415,7 +1416,6 @@ public class Launcher extends Activity // Setup the hotseat mHotseat = (Hotseat) findViewById(R.id.hotseat); if (mHotseat != null) { - mHotseat.setup(this); mHotseat.setOnLongClickListener(this); } @@ -1601,31 +1601,21 @@ public class Launcher extends Activity } } - static int[] getSpanForWidget(Context context, ComponentName component, int minWidth, - int minHeight) { - Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context, component, null); + private int[] getSpanForWidget(ComponentName component, int minWidth, int minHeight) { + Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(this, component, null); // We want to account for the extra amount of padding that we are adding to the widget // to ensure that it gets the full amount of space that it has requested int requiredWidth = minWidth + padding.left + padding.right; int requiredHeight = minHeight + padding.top + padding.bottom; - return CellLayout.rectToCell(requiredWidth, requiredHeight, null); - } - - static int[] getSpanForWidget(Context context, AppWidgetProviderInfo info) { - return getSpanForWidget(context, info.provider, info.minWidth, info.minHeight); + return CellLayout.rectToCell(this, requiredWidth, requiredHeight, null); } - static int[] getMinSpanForWidget(Context context, AppWidgetProviderInfo info) { - return getSpanForWidget(context, info.provider, info.minResizeWidth, info.minResizeHeight); + public int[] getSpanForWidget(AppWidgetProviderInfo info) { + return getSpanForWidget(info.provider, info.minWidth, info.minHeight); } - static int[] getSpanForWidget(Context context, PendingAddWidgetInfo info) { - return getSpanForWidget(context, info.componentName, info.minWidth, info.minHeight); - } - - static int[] getMinSpanForWidget(Context context, PendingAddWidgetInfo info) { - return getSpanForWidget(context, info.componentName, info.minResizeWidth, - info.minResizeHeight); + public int[] getMinSpanForWidget(AppWidgetProviderInfo info) { + return getSpanForWidget(info.provider, info.minResizeWidth, info.minResizeHeight); } /** @@ -1916,6 +1906,10 @@ public class Launcher extends Activity return mSharedPrefs; } + public DeviceProfile getDeviceProfile() { + return mDeviceProfile; + } + public void closeSystemDialogs() { getWindow().closeAllPanels(); @@ -4021,7 +4015,7 @@ public class Launcher extends Activity // Note: This assumes that the id remap broadcast is received before this step. // If that is not the case, the id remap will be ignored and user may see the // click to setup view. - PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, null); + PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null); pendingInfo.spanX = item.spanX; pendingInfo.spanY = item.spanY; pendingInfo.minSpanX = item.minSpanX; diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index f540eb47d..93753a201 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -57,7 +57,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { private static LauncherAppState INSTANCE; - private DynamicGrid mDynamicGrid; + private InvariantDeviceProfile mInvariantDeviceProfile; private LauncherAccessibilityDelegate mAccessibilityDelegate; public static LauncherAppState getInstance() { @@ -96,8 +96,9 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { // set sIsScreenXLarge and mScreenDensity *before* creating icon cache mIsScreenLarge = isScreenLarge(sContext.getResources()); mScreenDensity = sContext.getResources().getDisplayMetrics().density; - mIconCache = new IconCache(sContext); - mWidgetCache = new WidgetPreviewLoader(sContext, mIconCache); + mInvariantDeviceProfile = new InvariantDeviceProfile(sContext); + mIconCache = new IconCache(sContext, mInvariantDeviceProfile); + mWidgetCache = new WidgetPreviewLoader(sContext, mInvariantDeviceProfile, mIconCache); mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class)); mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class)); @@ -172,49 +173,6 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { return LauncherFiles.SHARED_PREFERENCES_KEY; } - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - DeviceProfile initDynamicGrid(Context context) { - mDynamicGrid = createDynamicGrid(context, mDynamicGrid); - mDynamicGrid.getDeviceProfile().addCallback(this); - return mDynamicGrid.getDeviceProfile(); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - static DynamicGrid createDynamicGrid(Context context, DynamicGrid dynamicGrid) { - // Determine the dynamic grid properties - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - - Point realSize = new Point(); - display.getRealSize(realSize); - DisplayMetrics dm = new DisplayMetrics(); - display.getMetrics(dm); - - if (dynamicGrid == null) { - Point smallestSize = new Point(); - Point largestSize = new Point(); - display.getCurrentSizeRange(smallestSize, largestSize); - - dynamicGrid = new DynamicGrid(context, - context.getResources(), - Math.min(smallestSize.x, smallestSize.y), - Math.min(largestSize.x, largestSize.y), - realSize.x, realSize.y, - dm.widthPixels, dm.heightPixels); - } - - // Update the icon size - DeviceProfile grid = dynamicGrid.getDeviceProfile(); - grid.updateFromConfiguration(context, context.getResources(), - realSize.x, realSize.y, - dm.widthPixels, dm.heightPixels); - return dynamicGrid; - } - - public DynamicGrid getDynamicGrid() { - return mDynamicGrid; - } - public WidgetPreviewLoader getWidgetCache() { return mWidgetCache; } @@ -251,6 +209,10 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { return result; } + public InvariantDeviceProfile getInvariantDeviceProfile() { + return mInvariantDeviceProfile; + } + @Override public void onAvailableSizeChanged(DeviceProfile grid) { Utilities.setIconSize(grid.iconSizePx); diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java index 954d2d711..71fb2d295 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java @@ -152,6 +152,10 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc return info; } + public LauncherAppWidgetProviderInfo getLauncherAppWidgetProviderInfo() { + return (LauncherAppWidgetProviderInfo) getAppWidgetInfo(); + } + @Override public void onTouchComplete() { if (!mLongPressHelper.hasPerformedLongPress()) { diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index e19bc9534..7ca4fe325 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -18,10 +18,11 @@ import android.os.Parcel; public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { public boolean isCustomWidget = false; - public int spanX = -1; - public int spanY = -1; - public int minSpanX = -1; - public int minSpanY = -1; + + private int mSpanX = -1; + private int mSpanY = -1; + private int mMinSpanX = -1; + private int mMinSpanY = -1; public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context, AppWidgetProviderInfo info) { @@ -35,15 +36,6 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { p.setDataPosition(0); LauncherAppWidgetProviderInfo lawpi = new LauncherAppWidgetProviderInfo(p); p.recycle(); - - int[] minResizeSpan = Launcher.getMinSpanForWidget(context, lawpi); - int[] span = Launcher.getSpanForWidget(context, lawpi); - - lawpi.spanX = span[0]; - lawpi.spanY = span[1]; - lawpi.minSpanX = minResizeSpan[0]; - lawpi.minSpanY = minResizeSpan[1]; - return lawpi; } @@ -60,11 +52,6 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { previewImage = widget.getPreviewImage(); initialLayout = widget.getWidgetLayout(); resizeMode = widget.getResizeMode(); - - spanX = widget.getSpanX(); - spanY = widget.getSpanY(); - minSpanX = widget.getMinSpanX(); - minSpanY = widget.getMinSpanY(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -87,7 +74,39 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { if (isCustomWidget) { return "WidgetProviderInfo(" + provider + ")"; } - return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s span(%d, %d) minSpan(%d, %d)", - provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm), spanX, spanY, minSpanX, minSpanY); + return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s", + provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm)); + } + + public int getSpanX(Launcher launcher) { + lazyLoadSpans(launcher); + return mSpanX; + } + + public int getSpanY(Launcher launcher) { + lazyLoadSpans(launcher); + return mSpanY; + } + + public int getMinSpanX(Launcher launcher) { + lazyLoadSpans(launcher); + return mMinSpanX; + } + + public int getMinSpanY(Launcher launcher) { + lazyLoadSpans(launcher); + return mMinSpanY; + } + + private void lazyLoadSpans(Launcher launcher) { + if (mSpanX < 0 || mSpanY < 0 || mMinSpanX < 0 || mMinSpanY < 0) { + int[] minResizeSpan = launcher.getMinSpanForWidget(this); + int[] span = launcher.getSpanForWidget(this); + + mSpanX = span[0]; + mSpanY = span[1]; + mMinSpanX = minResizeSpan[0]; + mMinSpanY = minResizeSpan[1]; + } } } diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 92bbb4019..af4101221 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -141,13 +141,15 @@ public class LauncherBackupHelper implements BackupHelper { private final ItemTypeMatcher[] mItemTypeMatchers; private final long mUserSerial; - private IconCache mIconCache; private BackupManager mBackupManager; private byte[] mBuffer = new byte[512]; private long mLastBackupRestoreTime; private boolean mBackupDataWasUpdated; - private DeviceProfieData mCurrentProfile; + private LauncherAppState mLauncherAppState; + private IconCache mIconCache; + private DeviceProfieData mDeviceProfileData; + boolean restoreSuccessful; int restoredBackupVersion = 1; @@ -197,10 +199,14 @@ public class LauncherBackupHelper implements BackupHelper { Journal in = readJournal(oldState); if (!launcherIsReady()) { + dataChanged(); // Perform backup later. writeJournal(newState, in); return; } + + lazyInitAppState(true /* noCreate */); + Log.v(TAG, "lastBackupTime = " + in.t); mKeys.clear(); applyJournal(in); @@ -296,12 +302,7 @@ public class LauncherBackupHelper implements BackupHelper { if (!restoreSuccessful) { return; } - if (!initializeIconCache()) { - // During restore we do not need an initialized instance of IconCache. We can create - // a temporary icon cache here, as the process will be rebooted after restore - // is complete. - mIconCache = new IconCache(mContext); - } + lazyInitAppState(false /* noCreate */); int dataSize = data.size(); if (mBuffer.length < dataSize) { @@ -395,19 +396,34 @@ public class LauncherBackupHelper implements BackupHelper { * @return the current device profile information. */ private DeviceProfieData getDeviceProfieData() { - if (mCurrentProfile != null) { - return mCurrentProfile; + return mDeviceProfileData; + } + + private void lazyInitAppState(boolean noCreate) { + if (mLauncherAppState != null) { + return; + } + + if (noCreate) { + mLauncherAppState = LauncherAppState.getInstanceNoCreate(); + } else { + LauncherAppState.setApplicationContext(mContext); + mLauncherAppState = LauncherAppState.getInstance(); } - final Context applicationContext = mContext.getApplicationContext(); - DeviceProfile profile = LauncherAppState.createDynamicGrid(applicationContext, null) - .getDeviceProfile(); - - mCurrentProfile = new DeviceProfieData(); - mCurrentProfile.desktopRows = profile.numRows; - mCurrentProfile.desktopCols = profile.numColumns; - mCurrentProfile.hotseatCount = profile.numHotseatIcons; - mCurrentProfile.allappsRank = profile.hotseatAllAppsRank; - return mCurrentProfile; + + mIconCache = mLauncherAppState.getIconCache(); + InvariantDeviceProfile profile = mLauncherAppState.getInvariantDeviceProfile(); + + mDeviceProfileData = initDeviceProfileData(profile); + } + + private DeviceProfieData initDeviceProfileData(InvariantDeviceProfile profile) { + DeviceProfieData data = new DeviceProfieData(); + data.desktopRows = profile.numRows; + data.desktopCols = profile.numColumns; + data.hotseatCount = profile.numHotseatIcons; + data.allappsRank = profile.hotseatAllAppsRank; + return data; } /** @@ -518,11 +534,6 @@ public class LauncherBackupHelper implements BackupHelper { */ private void backupIcons(BackupDataOutput data) throws IOException { // persist icons that haven't been persisted yet - if (!initializeIconCache()) { - dataChanged(); // try again later - if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying icon backup"); - return; - } final ContentResolver cr = mContext.getContentResolver(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); @@ -619,16 +630,9 @@ public class LauncherBackupHelper implements BackupHelper { */ private void backupWidgets(BackupDataOutput data) throws IOException { // persist static widget info that hasn't been persisted yet - final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); - if (appState == null || !initializeIconCache()) { - Log.w(TAG, "Failed to get icon cache during restore"); - return; - } final ContentResolver cr = mContext.getContentResolver(); - final WidgetPreviewLoader previewLoader = appState.getWidgetCache(); + final WidgetPreviewLoader previewLoader = mLauncherAppState.getWidgetCache(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; - final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile(); - if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx); int backupWidgetCount = 0; String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND " @@ -661,8 +665,7 @@ public class LauncherBackupHelper implements BackupHelper { if (DEBUG) Log.d(TAG, "saving widget " + backupKey); UserHandleCompat user = UserHandleCompat.myUserHandle(); writeRowToBackup(key, - packWidget(dpi, previewLoader,spanX * profile.cellWidthPx, - mIconCache, provider, user), + packWidget(dpi, previewLoader, mIconCache, provider, user), data); mKeys.add(key); backupWidgetCount ++; @@ -969,8 +972,7 @@ public class LauncherBackupHelper implements BackupHelper { } /** Serialize a widget for persistence, including a checksum wrapper. */ - private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, - int previewWidth, IconCache iconCache, + private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache, ComponentName provider, UserHandleCompat user) { final LauncherAppWidgetProviderInfo info = LauncherModel.getProviderInfo(mContext, provider, user); @@ -985,12 +987,6 @@ public class LauncherBackupHelper implements BackupHelper { widget.icon.data = Utilities.flattenBitmap(icon); widget.icon.dpi = dpi; } - if (info.previewImage != 0) { - widget.preview = new Resource(); - Bitmap preview = previewLoader.generateWidgetPreview(info, previewWidth, null); - widget.preview.data = Utilities.flattenBitmap(preview); - widget.preview.dpi = dpi; - } return widget; } @@ -1136,25 +1132,6 @@ public class LauncherBackupHelper implements BackupHelper { return wrapper.payload; } - private boolean initializeIconCache() { - if (mIconCache != null) { - return true; - } - - final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); - if (appState == null) { - if (DEBUG) { - Throwable stackTrace = new Throwable(); - stackTrace.fillInStackTrace(); - Log.w(TAG, "Failed to get app state during backup/restore", stackTrace); - } - return false; - } - mIconCache = appState.getIconCache(); - return mIconCache != null; - } - - /** * @return true if the launcher is in a state to support backup */ @@ -1167,9 +1144,8 @@ public class LauncherBackupHelper implements BackupHelper { } cursor.close(); - if (!initializeIconCache()) { + if (LauncherAppState.getInstanceNoCreate() == null) { // launcher services are unavailable, try again later - dataChanged(); return false; } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 1b9260290..8d321e668 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -422,9 +422,9 @@ public class LauncherModel extends BroadcastReceiver private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos, int[] xy, int spanX, int spanY) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - final int xCount = (int) grid.numColumns; - final int yCount = (int) grid.numRows; + InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); + final int xCount = (int) profile.numColumns; + final int yCount = (int) profile.numRows; boolean[][] occupied = new boolean[xCount][yCount]; if (occupiedPos != null) { for (ItemInfo r : occupiedPos) { @@ -1663,9 +1663,9 @@ public class LauncherModel extends BroadcastReceiver // check & update map of what's occupied; used to discard overlapping/invalid items private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - final int countX = (int) grid.numColumns; - final int countY = (int) grid.numRows; + InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); + final int countX = (int) profile.numColumns; + final int countY = (int) profile.numRows; long containerIndex = item.screenId; if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { @@ -1681,10 +1681,10 @@ public class LauncherModel extends BroadcastReceiver final ItemInfo[][] hotseatItems = occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT); - if (item.screenId >= grid.numHotseatIcons) { + if (item.screenId >= profile.numHotseatIcons) { Log.e(TAG, "Error loading shortcut " + item + " into hotseat position " + item.screenId - + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1) + + ", position out of bounds: (0 to " + (profile.numHotseatIcons - 1) + ")"); return false; } @@ -1702,7 +1702,7 @@ public class LauncherModel extends BroadcastReceiver return true; } } else { - final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1]; + final ItemInfo[][] items = new ItemInfo[(int) profile.numHotseatIcons][1]; items[(int) item.screenId][0] = item; occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items); return true; @@ -1776,9 +1776,9 @@ public class LauncherModel extends BroadcastReceiver new IntentFilter(StartupReceiver.SYSTEM_READY)) != null; LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - int countX = (int) grid.numColumns; - int countY = (int) grid.numRows; + InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); + int countX = (int) profile.numColumns; + int countY = (int) profile.numRows; if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) { Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true); @@ -2190,13 +2190,6 @@ public class LauncherModel extends BroadcastReceiver appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, provider.provider); - if (!customWidget) { - int[] minSpan = - Launcher.getMinSpanForWidget(context, provider); - appWidgetInfo.minSpanX = minSpan[0]; - appWidgetInfo.minSpanY = minSpan[1]; - } - int status = restoreStatus; if (!wasProviderReady) { // If provider was not previously ready, update the @@ -2244,12 +2237,6 @@ public class LauncherModel extends BroadcastReceiver appWidgetInfo.spanX = c.getInt(spanXIndex); appWidgetInfo.spanY = c.getInt(spanYIndex); - if (!customWidget) { - int[] minSpan = Launcher.getMinSpanForWidget(context, provider); - appWidgetInfo.minSpanX = minSpan[0]; - appWidgetInfo.minSpanY = minSpan[1]; - } - container = c.getInt(containerIndex); if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP && container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) { @@ -2512,13 +2499,13 @@ public class LauncherModel extends BroadcastReceiver * right) */ private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) { final LauncherAppState app = LauncherAppState.getInstance(); - final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + final InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); // XXX: review this Collections.sort(workspaceItems, new Comparator<ItemInfo>() { @Override public int compare(ItemInfo lhs, ItemInfo rhs) { - int cellCountX = (int) grid.numColumns; - int cellCountY = (int) grid.numRows; + int cellCountX = (int) profile.numColumns; + int cellCountY = (int) profile.numRows; int screenOffset = cellCountX * cellCountY; int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset + diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 8fef32daa..27511527d 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -364,7 +364,7 @@ public class LauncherProvider extends ContentProvider { private DefaultLayoutParser getDefaultLayoutParser() { int defaultLayout = LauncherAppState.getInstance() - .getDynamicGrid().getDeviceProfile().defaultLayoutId; + .getInvariantDeviceProfile().defaultLayoutId; return new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost, mOpenHelper, getContext().getResources(), defaultLayout); } @@ -1042,10 +1042,10 @@ public class LauncherProvider extends ContentProvider { int curY = 0; final LauncherAppState app = LauncherAppState.getInstance(); - final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - final int width = (int) grid.numColumns; - final int height = (int) grid.numRows; - final int hotseatWidth = (int) grid.numHotseatIcons; + final InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); + final int width = (int) profile.numColumns; + final int height = (int) profile.numRows; + final int hotseatWidth = (int) profile.numHotseatIcons; final HashSet<String> seenIntents = new HashSet<String>(c.getCount()); @@ -1187,7 +1187,7 @@ public class LauncherProvider extends ContentProvider { int hotseatX = hotseat.keyAt(idx); ContentValues values = hotseat.valueAt(idx); - if (hotseatX == grid.hotseatAllAppsRank) { + if (hotseatX == profile.hotseatAllAppsRank) { // let's drop this in the next available hole in the hotseat while (++hotseatX < hotseatWidth) { if (hotseat.get(hotseatX) == null) { diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index 324375444..ce13da66e 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -156,8 +156,7 @@ public class LauncherStateTransitionAnimation { } @Override public float getMaterialRevealViewStartFinalRadius() { - int allAppsButtonSize = LauncherAppState.getInstance(). - getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize; + int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize; return allAppsButtonSize / 2; } @Override @@ -456,8 +455,7 @@ public class LauncherStateTransitionAnimation { } @Override float getMaterialRevealViewStartFinalRadius() { - int allAppsButtonSize = LauncherAppState.getInstance(). - getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize; + int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize; return allAppsButtonSize / 2; } @Override diff --git a/src/com/android/launcher3/Partner.java b/src/com/android/launcher3/Partner.java index e1913193b..c9e837994 100644 --- a/src/com/android/launcher3/Partner.java +++ b/src/com/android/launcher3/Partner.java @@ -116,56 +116,70 @@ public class Partner { return resId != 0 && getResources().getBoolean(resId); } - public DeviceProfile getDeviceProfileOverride(DisplayMetrics dm) { - boolean containsProfileOverrides = false; - - DeviceProfile dp = new DeviceProfile(); - - // We initialize customizable fields to be invalid - dp.numRows = -1; - dp.numColumns = -1; - dp.allAppsShortEdgeCount = -1; - dp.allAppsLongEdgeCount = -1; + public void applyInvariantDeviceProfileOverrides(InvariantDeviceProfile inv, DisplayMetrics dm) { + int numRows = -1; + int numColumns = -1; + float iconSize = -1; try { int resId = getResources().getIdentifier(RES_GRID_NUM_ROWS, "integer", getPackageName()); if (resId > 0) { - containsProfileOverrides = true; - dp.numRows = getResources().getInteger(resId); + numRows = getResources().getInteger(resId); } resId = getResources().getIdentifier(RES_GRID_NUM_COLUMNS, "integer", getPackageName()); if (resId > 0) { - containsProfileOverrides = true; - dp.numColumns = getResources().getInteger(resId); + numColumns = getResources().getInteger(resId); } - resId = getResources().getIdentifier(RES_GRID_AA_SHORT_EDGE_COUNT, - "integer", getPackageName()); + resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP, + "dimen", getPackageName()); if (resId > 0) { - containsProfileOverrides = true; - dp.allAppsShortEdgeCount = getResources().getInteger(resId); + int px = getResources().getDimensionPixelSize(resId); + iconSize = Utilities.dpiFromPx(px, dm); } + } catch (Resources.NotFoundException ex) { + Log.e(TAG, "Invalid Partner grid resource!", ex); + return; + } - resId = getResources().getIdentifier(RES_GRID_AA_LONG_EDGE_COUNT, + if (numRows > 0 && numColumns > 0) { + inv.numRows = numRows; + inv.numColumns = numColumns; + } + + if (iconSize > 0) { + inv.iconSize = iconSize; + } + } + + public void applyDeviceProfileOverrides(DeviceProfile dp) { + int allAppsShortEdgeCount = -1; + int allAppsLongEdgeCount = -1; + + try { + int resId = getResources().getIdentifier(RES_GRID_AA_SHORT_EDGE_COUNT, "integer", getPackageName()); if (resId > 0) { - containsProfileOverrides = true; - dp.allAppsLongEdgeCount = getResources().getInteger(resId); + allAppsShortEdgeCount = getResources().getInteger(resId); } - resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP, - "dimen", getPackageName()); + resId = getResources().getIdentifier(RES_GRID_AA_LONG_EDGE_COUNT, + "integer", getPackageName()); if (resId > 0) { - containsProfileOverrides = true; - int px = getResources().getDimensionPixelSize(resId); - dp.iconSize = DynamicGrid.dpiFromPx(px, dm); + allAppsLongEdgeCount = getResources().getInteger(resId); } + } catch (Resources.NotFoundException ex) { Log.e(TAG, "Invalid Partner grid resource!", ex); + return; + } + + if (allAppsShortEdgeCount > 0 && allAppsLongEdgeCount > 0) { + dp.allAppsShortEdgeCount = allAppsShortEdgeCount; + dp.allAppsLongEdgeCount = allAppsLongEdgeCount; } - return containsProfileOverrides ? dp : null; } } diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java index 179c60a98..c8b27efd3 100644 --- a/src/com/android/launcher3/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/PendingAppWidgetHostView.java @@ -42,6 +42,7 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen private final int mStartState; private final Intent mIconLookupIntent; private final boolean mDisabledForSafeMode; + private Launcher mLauncher; private Bitmap mIcon; @@ -56,6 +57,8 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info, boolean disabledForSafeMode) { super(context); + + mLauncher = (Launcher) context; mInfo = info; mStartState = info.restoreStatus; mIconLookupIntent = new Intent().setComponent(info.providerName); @@ -64,7 +67,7 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen mPaint = new TextPaint(); mPaint.setColor(0xFFFFFFFF); mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, - getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics())); + mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics())); setBackgroundResource(R.drawable.quantum_panel_dark); setWillNotDraw(false); } @@ -173,12 +176,12 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen return; } + DeviceProfile grid = mLauncher.getDeviceProfile(); if (mTopCornerDrawable == null) { if (mDrawableSizeChanged) { int outset = (mCenterDrawable instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) mCenterDrawable).getOutset() : 0; - int maxSize = LauncherAppState.getInstance().getDynamicGrid() - .getDeviceProfile().iconSizePx + 2 * outset; + int maxSize = grid.iconSizePx + 2 * outset; int size = Math.min(maxSize, Math.min( getWidth() - getPaddingLeft() - getPaddingRight(), getHeight() - getPaddingTop() - getPaddingBottom())); @@ -193,7 +196,6 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen } else { // Draw the top corner icon and "Setup" text is possible if (mDrawableSizeChanged) { - DeviceProfile grid = getDeviceProfile(); int iconSize = grid.iconSizePx; int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); @@ -251,8 +253,4 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen } } } - - private DeviceProfile getDeviceProfile() { - return LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); - } } diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 490ed6a73..157b48a39 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -45,10 +45,13 @@ public class ShortcutAndWidgetContainer extends ViewGroup { private int mCountX; private int mCountY; + private Launcher mLauncher; + private boolean mInvertIfRtl = false; public ShortcutAndWidgetContainer(Context context) { super(context); + mLauncher = (Launcher) context; mWallpaperManager = WallpaperManager.getInstance(context); } @@ -125,22 +128,19 @@ public class ShortcutAndWidgetContainer extends ViewGroup { } int getCellContentWidth() { - final LauncherAppState app = LauncherAppState.getInstance(); - final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + final DeviceProfile grid = mLauncher.getDeviceProfile(); return Math.min(getMeasuredHeight(), mIsHotseatLayout ? grid.hotseatCellWidthPx: grid.cellWidthPx); } int getCellContentHeight() { - final LauncherAppState app = LauncherAppState.getInstance(); - final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + final DeviceProfile grid = mLauncher.getDeviceProfile(); return Math.min(getMeasuredHeight(), mIsHotseatLayout ? grid.hotseatCellHeightPx : grid.cellHeightPx); } public void measureChild(View child) { - final LauncherAppState app = LauncherAppState.getInstance(); - final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + final DeviceProfile grid = mLauncher.getDeviceProfile(); final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 9f47e138d..6c4b7207b 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -46,9 +46,11 @@ import android.graphics.drawable.PaintDrawable; import android.os.Build; import android.os.Process; import android.text.TextUtils; +import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.util.SparseArray; +import android.util.TypedValue; import android.view.View; import android.widget.Toast; @@ -669,4 +671,17 @@ public final class Utilities { && launchIntent.getExtras() == null && TextUtils.isEmpty(launchIntent.getDataString()); } + + public static float dpiFromPx(int size, DisplayMetrics metrics){ + float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT; + return (size / densityRatio); + } + public static int pxFromDp(float size, DisplayMetrics metrics) { + return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + size, metrics)); + } + public static int pxFromSp(float size, DisplayMetrics metrics) { + return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + size, metrics)); + } } diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 5ee1f2615..1cf3bc469 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -66,17 +66,19 @@ public class WidgetPreviewLoader { private final UserManagerCompat mUserManager; private final AppWidgetManagerCompat mManager; private final CacheDb mDb; + private final InvariantDeviceProfile mDeviceProfile; private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); private final Handler mWorkerHandler; - public WidgetPreviewLoader(Context context, IconCache iconCache) { + public WidgetPreviewLoader(Context context, InvariantDeviceProfile inv, IconCache iconCache) { mContext = context; mIconCache = iconCache; mManager = AppWidgetManagerCompat.getInstance(context); mUserManager = UserManagerCompat.getInstance(context); mDb = new CacheDb(context); mWorkerHandler = new Handler(LauncherModel.getWorkerLooper()); + mDeviceProfile = inv; } /** @@ -86,8 +88,8 @@ public class WidgetPreviewLoader { * @param o either {@link LauncherAppWidgetProviderInfo} or {@link ResolveInfo} * @return a request id which can be used to cancel the request. */ - public PreviewLoadRequest getPreview(final Object o, int previewWidth, int previewHeight, - WidgetCell caller) { + public PreviewLoadRequest getPreview(final Object o, int previewWidth, + int previewHeight, WidgetCell caller) { String size = previewWidth + "x" + previewHeight; WidgetCacheKey key = getObjectKey(o, size); @@ -329,23 +331,18 @@ public class WidgetPreviewLoader { return null; } - private Bitmap generatePreview(Object info, Bitmap recycle, int previewWidth, int previewHeight) { + private Bitmap generatePreview(Launcher launcher, Object info, Bitmap recycle, + int previewWidth, int previewHeight) { if (info instanceof LauncherAppWidgetProviderInfo) { - return generateWidgetPreview((LauncherAppWidgetProviderInfo) info, previewWidth, recycle); + return generateWidgetPreview(launcher, (LauncherAppWidgetProviderInfo) info, + previewWidth, recycle, null); } else { - return generateShortcutPreview( + return generateShortcutPreview(launcher, (ResolveInfo) info, previewWidth, previewHeight, recycle); } } - public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, - int previewWidth, Bitmap preview) { - int maxWidth = Math.min(previewWidth, info.spanX - * LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile().cellWidthPx); - return generateWidgetPreview(info, maxWidth, preview, null); - } - - public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, + public Bitmap generateWidgetPreview(Launcher launcher, LauncherAppWidgetProviderInfo info, int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) { // Load the preview image if possible if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; @@ -362,8 +359,8 @@ public class WidgetPreviewLoader { } final boolean widgetPreviewExists = (drawable != null); - final int spanX = info.spanX < 1 ? 1 : info.spanX; - final int spanY = info.spanY < 1 ? 1 : info.spanY; + final int spanX = info.getSpanX(launcher) < 1 ? 1 : info.getSpanX(launcher); + final int spanY = info.getSpanY(launcher) < 1 ? 1 : info.getSpanY(launcher); int previewWidth; int previewHeight; @@ -413,8 +410,7 @@ public class WidgetPreviewLoader { } else { final Paint p = new Paint(); p.setFilterBitmap(true); - int appIconSize = LauncherAppState.getInstance().getDynamicGrid() - .getDeviceProfile().iconSizePx; + int appIconSize = launcher.getDeviceProfile().iconSizePx; // draw the spanX x spanY tiles final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight()); @@ -455,7 +451,7 @@ public class WidgetPreviewLoader { } private Bitmap generateShortcutPreview( - ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { + Launcher launcher, ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { final Canvas c = new Canvas(); if (preview == null) { preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); @@ -488,8 +484,8 @@ public class WidgetPreviewLoader { // Draw the final icon at top left corner. // TODO: use top right for RTL - int appIconSize = LauncherAppState.getInstance().getDynamicGrid() - .getDeviceProfile().iconSizePx; + int appIconSize = launcher.getDeviceProfile().iconSizePx; + icon.setAlpha(255); icon.setColorFilter(null); icon.setBounds(0, 0, appIconSize, appIconSize); @@ -626,8 +622,10 @@ public class WidgetPreviewLoader { // which would gets re-written next time. mVersions = getPackageVersion(mKey.componentName.getPackageName()); + Launcher launcher = (Launcher) mCaller.getContext(); + // it's not in the db... we need to generate it - preview = generatePreview(mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight); + preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight); } return preview; } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 55742f655..67155d0b1 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -307,13 +307,11 @@ public class Workspace extends SmoothPagedView mLauncher = (Launcher) context; mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this); final Resources res = getResources(); - mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid(). - getDeviceProfile().shouldFadeAdjacentWorkspaceScreens(); + DeviceProfile grid = mLauncher.getDeviceProfile(); + mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens(); mFadeInAdjacentScreens = false; mWallpaperManager = WallpaperManager.getInstance(context); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0); mSpringLoadedShrinkFactor = @@ -422,7 +420,7 @@ public class Workspace extends SmoothPagedView protected void initWorkspace() { mCurrentPage = mDefaultPage; LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); mIconCache = app.getIconCache(); setWillNotDraw(false); setClipChildren(false); @@ -1901,8 +1899,7 @@ public class Workspace extends SmoothPagedView public void onExternalDragStartedWithItem(View v) { // Compose a drag bitmap with the view scaled to the icon size - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int iconSize = grid.iconSizePx; int bmpWidth = v.getMeasuredWidth(); int bmpHeight = v.getMeasuredHeight(); @@ -1984,7 +1981,7 @@ public class Workspace extends SmoothPagedView int getOverviewModeTranslationY() { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); Rect overviewBar = grid.getOverviewModeButtonBarRect(); int availableHeight = getViewportHeight(); @@ -2285,8 +2282,7 @@ public class Workspace extends SmoothPagedView int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2 - padding.get() / 2); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); Point dragVisualizeOffset = null; Rect dragRect = null; if (child instanceof BubbleTextView) { @@ -2343,7 +2339,7 @@ public class Workspace extends SmoothPagedView public void beginExternalDragShared(View child, DragSource source) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int iconSize = grid.iconSizePx; // Notify launcher of drag start @@ -2852,14 +2848,14 @@ public class Workspace extends SmoothPagedView * widthGap/heightGap (right, bottom) */ static Rect getCellLayoutMetrics(Launcher launcher, int orientation) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = launcher.getDeviceProfile(); Display display = launcher.getWindowManager().getDefaultDisplay(); Point smallestSize = new Point(); Point largestSize = new Point(); display.getCurrentSizeRange(smallestSize, largestSize); - int countX = (int) grid.numColumns; - int countY = (int) grid.numRows; + int countX = (int) grid.inv.numColumns; + int countY = (int) grid.inv.numRows; if (orientation == CellLayout.LANDSCAPE) { if (mLandscapeCellLayoutMetrics == null) { Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE); @@ -3023,7 +3019,7 @@ public class Workspace extends SmoothPagedView mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true); LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); r = grid.getHotseatRect(); if (r.contains(mTempPt[0], mTempPt[1])) { return true; diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 61a64e3f3..5744531af 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -162,7 +162,7 @@ public class WorkspaceStateTransitionAnimation { mWorkspace = workspace; LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); Resources res = launcher.getResources(); mAllAppsTransitionTime = res.getInteger(R.integer.config_workspaceUnshrinkTime); mOverviewTransitionTime = res.getInteger(R.integer.config_overviewTransitionTime); diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java index a84e7df03..696eabe00 100644 --- a/src/com/android/launcher3/util/FocusLogic.java +++ b/src/com/android/launcher3/util/FocusLogic.java @@ -23,6 +23,7 @@ import android.view.ViewGroup; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.ShortcutAndWidgetContainer; @@ -80,8 +81,8 @@ public class FocusLogic { keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL); } - public static int handleKeyEvent(int keyCode, int cntX, int cntY, int [][] map, - int iconIdx, int pageIndex, int pageCount) { + public static int handleKeyEvent(int keyCode, int cntX, int cntY, + int [][] map, int iconIdx, int pageIndex, int pageCount, boolean isRtl) { if (DEBUG) { Log.v(TAG, String.format( @@ -89,23 +90,21 @@ public class FocusLogic { cntX, cntY, iconIdx, pageIndex, pageCount)); } - DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid() - .getDeviceProfile(); int newIndex = NOOP; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, -1 /*increment*/); - if (!profile.isLayoutRtl && newIndex == NOOP && pageIndex > 0) { + if (isRtl && newIndex == NOOP && pageIndex > 0) { newIndex = PREVIOUS_PAGE_RIGHT_COLUMN; - } else if (profile.isLayoutRtl && newIndex == NOOP && pageIndex < pageCount - 1) { + } else if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) { newIndex = NEXT_PAGE_RIGHT_COLUMN; } break; case KeyEvent.KEYCODE_DPAD_RIGHT: newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, 1 /*increment*/); - if (!profile.isLayoutRtl && newIndex == NOOP && pageIndex < pageCount - 1) { + if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) { newIndex = NEXT_PAGE_LEFT_COLUMN; - } else if (profile.isLayoutRtl && newIndex == NOOP && pageIndex > 0) { + } else if (isRtl && newIndex == NOOP && pageIndex > 0) { newIndex = PREVIOUS_PAGE_LEFT_COLUMN; } break; diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java index db1699818..36cc2b111 100644 --- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java +++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java @@ -19,6 +19,7 @@ import android.appwidget.AppWidgetHostView; import android.os.Bundle; import android.os.Parcelable; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.PendingAddItemInfo; @@ -39,7 +40,7 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo { public AppWidgetHostView boundWidget; public Bundle bindOptions = null; - public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) { + public PendingAddWidgetInfo(Launcher launcher, LauncherAppWidgetProviderInfo i, Parcelable data) { if (i.isCustomWidget) { itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; } else { @@ -54,10 +55,10 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo { previewImage = i.previewImage; icon = i.icon; - spanX = i.spanX; - spanY = i.spanY; - minSpanX = i.minSpanX; - minSpanY = i.minSpanY; + spanX = i.getSpanX(launcher); + spanY = i.getSpanY(launcher); + minSpanX = i.getMinSpanX(launcher); + minSpanY = i.getMinSpanY(launcher); } public boolean isCustomWidget() { diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index dcaf1f211..3ec164506 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -29,7 +29,9 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; @@ -72,6 +74,8 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { private WidgetPreviewLoader mWidgetPreviewLoader; private PreviewLoadRequest mActiveRequest; + private Launcher mLauncher; + public WidgetCell(Context context) { this(context, null); } @@ -84,8 +88,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { super(context, attrs, defStyle); final Resources r = context.getResources(); - mDimensionsFormatString = r.getString(R.string.widget_dims_format); + mLauncher = (Launcher) context; + mDimensionsFormatString = r.getString(R.string.widget_dims_format); setContainerWidth(); setWillNotDraw(false); setClipToPadding(false); @@ -93,9 +98,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { } private void setContainerWidth() { - DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile profile = mLauncher.getDeviceProfile(); cellSize = (int) (profile.cellWidthPx * WIDTH_SCALE); - mPresetPreviewSize = (int) (profile.cellWidthPx * WIDTH_SCALE * PREVIEW_SCALE); + mPresetPreviewSize = (int) (cellSize * PREVIEW_SCALE); } @Override @@ -130,14 +135,14 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { */ public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info, WidgetPreviewLoader loader) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + InvariantDeviceProfile profile = + LauncherAppState.getInstance().getInvariantDeviceProfile(); mInfo = info; // TODO(hyunyoungs): setup a cache for these labels. mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); - int hSpan = Math.min(info.spanX, grid.numColumns); - int vSpan = Math.min(info.spanY, grid.numRows); + int hSpan = Math.min(info.getSpanX(mLauncher), profile.numColumns); + int vSpan = Math.min(info.getSpanY(mLauncher), profile.numRows); mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); mWidgetPreviewLoader = loader; } @@ -192,8 +197,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { public int getActualItemWidth() { ItemInfo info = (ItemInfo) getTag(); int[] size = getPreviewSize(); - int cellWidth = LauncherAppState.getInstance() - .getDynamicGrid().getDeviceProfile().cellWidthPx; + int cellWidth = mLauncher.getDeviceProfile().cellWidthPx; return Math.min(size[0], info.spanX * cellWidth); } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 5a879faa0..05e842e71 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -109,7 +109,7 @@ public class WidgetsContainerView extends BaseContainerView mView.setLayoutManager(new LinearLayoutManager(getContext()) { @Override protected int getExtraLayoutSpace(State state) { - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); return super.getExtraLayoutSpace(state) + grid.availableHeightPx * PRELOAD_SCREEN_HEIGHT_MULTIPLE; } @@ -230,8 +230,8 @@ public class WidgetsContainerView extends BaseContainerView int maxWidth = Math.min((int) (icon.getWidth() * minScale), size[0]); int[] previewSizeBeforeScale = new int[1]; - preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info, - maxWidth, null, previewSizeBeforeScale); + preview = getWidgetPreviewLoader().generateWidgetPreview(mLauncher, + createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale); if (previewSizeBeforeScale[0] < icon.getWidth()) { // The icon has extra padding around it. diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java index 918ec1bda..7439a44f8 100644 --- a/src/com/android/launcher3/widget/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java @@ -32,11 +32,12 @@ import android.widget.LinearLayout; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DynamicGrid; +import com.android.launcher3.IconCache; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.model.WidgetsModel; @@ -56,7 +57,6 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> { private static final String TAG = "WidgetsListAdapter"; private static final boolean DEBUG = true; - private Context mContext; private Launcher mLauncher; private LayoutInflater mLayoutInflater; @@ -74,7 +74,6 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> { View.OnLongClickListener iconLongClickListener, Launcher launcher) { mLayoutInflater = LayoutInflater.from(context); - mContext = context; mIconClickListener = iconClickListener; mIconLongClickListener = iconLongClickListener; @@ -141,7 +140,7 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> { WidgetCell widget = (WidgetCell) row.getChildAt(i); if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) { LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i); - PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(info, null); + PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(mLauncher, info, null); widget.setTag(pawi); widget.applyFromAppWidgetProviderInfo(info, mWidgetPreviewLoader); } else if (infoList.get(i) instanceof ResolveInfo) { @@ -206,10 +205,10 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> { } private void setContainerHeight() { - Resources r = mContext.getResources(); - DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + Resources r = mLauncher.getResources(); + DeviceProfile profile = mLauncher.getDeviceProfile(); if (profile.isLargeTablet || profile.isTablet) { - mIndent = DynamicGrid.pxFromDp(PRESET_INDENT_SIZE_TABLET, r.getDisplayMetrics()); + mIndent = Utilities.pxFromDp(PRESET_INDENT_SIZE_TABLET, r.getDisplayMetrics()); } } } |