19258b6bc66e09368ada54001f619d53b4fc976d5ager@chromium.org/* 23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * Copyright (C) 2011 The Android Open Source Project 33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * 443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Licensed under the Apache License, Version 2.0 (the "License"); 543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * you may not use this file except in compliance with the License. 643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * You may obtain a copy of the License at 743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * 843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * http://www.apache.org/licenses/LICENSE-2.0 943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * 1043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Unless required by applicable law or agreed to in writing, software 1143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * distributed under the License is distributed on an "AS IS" BASIS, 1243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * See the License for the specific language governing permissions and 1443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * limitations under the License. 1543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 1643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenpackage com.android.launcher2; 1843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 19f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.animation.AnimatorSet; 20f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.animation.ValueAnimator; 21f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.appwidget.AppWidgetHostView; 22f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.appwidget.AppWidgetManager; 23f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.appwidget.AppWidgetProviderInfo; 24f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.content.ComponentName; 25f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.content.Context; 26f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.orgimport android.content.Intent; 2788d326b0935b802e71e3a75e02f31fae8c2af96cmstarzinger@chromium.orgimport android.content.pm.LauncherActivityInfo; 2843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.content.pm.LauncherApps; 29fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.content.pm.PackageManager; 3043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.content.pm.ResolveInfo; 317c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.orgimport android.content.res.Configuration; 3243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.content.res.Resources; 3343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.content.res.TypedArray; 3443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.graphics.Bitmap; 3543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.graphics.Canvas; 36fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.graphics.Point; 37fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.graphics.Rect; 38fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.graphics.drawable.Drawable; 3931c0e32e19ad3df48525fa9e7b2d1c0c07496d00machenbach@chromium.orgimport android.os.AsyncTask; 40fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.os.Build; 41fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.os.Bundle; 42fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.os.Process; 43fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.util.AttributeSet; 44fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.util.Log; 45fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.util.SparseArray; 4643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.view.Gravity; 47fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.view.KeyEvent; 48fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.view.LayoutInflater; 49f705b5034dc5bc422ac1019b591469a7d0534772mstarzinger@chromium.orgimport android.view.View; 50fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.view.ViewGroup; 51fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.view.animation.AccelerateInterpolator; 52fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.view.animation.DecelerateInterpolator; 53fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.widget.GridLayout; 54fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport android.widget.ImageView; 55f705b5034dc5bc422ac1019b591469a7d0534772mstarzinger@chromium.orgimport android.widget.Toast; 56f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 57f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgimport com.android.launcher.R; 58fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport com.android.launcher2.DropTarget.DragObject; 59fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org 60fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport java.util.ArrayList; 6143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport java.util.Collections; 62fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orgimport java.util.Iterator; 63f705b5034dc5bc422ac1019b591469a7d0534772mstarzinger@chromium.orgimport java.util.List; 64fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org 65fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org/** 6643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * A simple callback interface which also provides the results of the task. 67fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org */ 68fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.orginterface AsyncTaskCallback { 6943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data); 70fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org} 714980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org 729258b6bc66e09368ada54001f619d53b4fc976d5ager@chromium.org/** 739258b6bc66e09368ada54001f619d53b4fc976d5ager@chromium.org * The data needed to perform either of the custom AsyncTasks. 74fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org */ 75f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgclass AsyncTaskPageData { 76fb144a0716afe7ab8bf245f2391a9e53b3db3c89fschneider@chromium.org enum Type { 7743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen LoadWidgetPreviewData 7843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 7943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 8041044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR, 8143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen AsyncTaskCallback postR, WidgetPreviewLoader w) { 8243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen page = p; 8343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen items = l; 8443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen generatedImages = new ArrayList<Bitmap>(); 8543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen maxImageWidth = cw; 8643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen maxImageHeight = ch; 87eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org doInBackgroundCallback = bgR; 889258b6bc66e09368ada54001f619d53b4fc976d5ager@chromium.org postExecuteCallback = postR; 897c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org widgetPreviewLoader = w; 907c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org } 917c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org void cleanup(boolean cancelled) { 92eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org // Clean up any references to source/generated bitmaps 939258b6bc66e09368ada54001f619d53b4fc976d5ager@chromium.org if (generatedImages != null) { 948ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org if (cancelled) { 958ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org for (int i = 0; i < generatedImages.size(); i++) { 968ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org widgetPreviewLoader.recycleBitmap(items.get(i), generatedImages.get(i)); 979258b6bc66e09368ada54001f619d53b4fc976d5ager@chromium.org } 9841044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org } 9943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen generatedImages.clear(); 10043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 10143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 10243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int page; 10343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen ArrayList<Object> items; 1040c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org ArrayList<Bitmap> sourceImages; 10532d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org ArrayList<Bitmap> generatedImages; 1060c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org int maxImageWidth; 1070c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org int maxImageHeight; 1080c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org AsyncTaskCallback doInBackgroundCallback; 1090c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org AsyncTaskCallback postExecuteCallback; 1100c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org WidgetPreviewLoader widgetPreviewLoader; 1110c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org} 1120c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org 1130c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org/** 1140c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org * A generic template for an async task used in AppsCustomize. 1150c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org */ 11632d961d4454609ab4251a760fc46b19f661da90clrn@chromium.orgclass AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTaskPageData> { 11732d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org AppsCustomizeAsyncTask(int p, AsyncTaskPageData.Type ty) { 11832d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org page = p; 11932d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org threadPriority = Process.THREAD_PRIORITY_DEFAULT; 12032d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org dataType = ty; 12132d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org } 12213bd294acf56c7f824d92d4941a2aeb3cec58e0ckmillikin@chromium.org @Override 1230c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org protected AsyncTaskPageData doInBackground(AsyncTaskPageData... params) { 1240c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org if (params.length != 1) return null; 12513bd294acf56c7f824d92d4941a2aeb3cec58e0ckmillikin@chromium.org // Load each of the widget previews in the background 12613bd294acf56c7f824d92d4941a2aeb3cec58e0ckmillikin@chromium.org params[0].doInBackgroundCallback.run(this, params[0]); 12732d961d4454609ab4251a760fc46b19f661da90clrn@chromium.org return params[0]; 1280c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org } 1290c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org @Override 13043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen protected void onPostExecute(AsyncTaskPageData result) { 1310c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org // All the widget previews are loaded, so we can just callback to inflate the page 1320c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org result.postExecuteCallback.run(this, result); 1330c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org } 1340c20e676f8a0209982ff89e5a9c707771748a585fschneider@chromium.org 13543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen void setThreadPriority(int p) { 13641044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org threadPriority = p; 13743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 13843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen void syncThreadPriority() { 13943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Process.setThreadPriority(threadPriority); 14043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 14143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 14243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // The page that this async task is associated with 14343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen AsyncTaskPageData.Type dataType; 14443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int page; 14543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int threadPriority; 14643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen} 14743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1487c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org/** 149ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org * The Apps/Customize page that displays all the applications, widgets, and shortcuts. 15041044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org */ 1517c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.orgpublic class AppsCustomizePagedView extends PagedViewWithDraggableItems implements 15243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen View.OnClickListener, View.OnKeyListener, DragSource, 15343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener, 154eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org LauncherTransitionable { 15543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen static final String TAG = "AppsCustomizePagedView"; 156ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org 15743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** 158d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org * The different content types that this paged view can show. 15943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 16043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public enum ContentType { 16143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Applications, 16241044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org Widgets 16343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 16443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1658ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org // Refs 166eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private Launcher mLauncher; 16786f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private DragController mDragController; 168ea4f62e1df22417fc8dc2c2425485dca98b13d07ager@chromium.org private final LayoutInflater mLayoutInflater; 16986f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private final PackageManager mPackageManager; 17086f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org 17186f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org // Save and Restore 1725c838251403b0be9a882540f1922577abba4c872ager@chromium.org private int mSaveInstanceStateItemIndex = -1; 17386f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private PagedViewIcon mPressedIcon; 17486f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org 17586f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org // Content 176ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org private ArrayList<ApplicationInfo> mApps; 1778ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org private ArrayList<Object> mWidgets; 1788ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org 1798ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org // Cling 180eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private boolean mHasShownAllAppsCling; 181eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private int mClingFocusedX; 18286f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private int mClingFocusedY; 18386f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org 184ea4f62e1df22417fc8dc2c2425485dca98b13d07ager@chromium.org // Caching 18586f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private Canvas mCanvas; 18686f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private IconCache mIconCache; 18786f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org 1885c838251403b0be9a882540f1922577abba4c872ager@chromium.org // Dimens 18986f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private int mContentWidth; 19086f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private int mMaxAppCellCountX, mMaxAppCellCountY; 19186f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org private int mWidgetCountX, mWidgetCountY; 192ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org private int mWidgetWidthGap, mWidgetHeightGap; 1938ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org private PagedViewCellLayout mWidgetSpacingLayout; 1948ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org private int mNumAppsPages; 1958ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org private int mNumWidgetPages; 19643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 197eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org // Relating to the scroll and overscroll effects 198d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f); 199d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org private static float CAMERA_DISTANCE = 6500; 200eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private static float TRANSITION_SCALE_FACTOR = 0.74f; 20141044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org private static float TRANSITION_PIVOT = 0.65f; 20243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private static float TRANSITION_MAX_ROTATION = 22; 20343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private static final boolean PERFORM_OVERSCROLL_ROTATION = true; 20443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f); 205eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4); 206d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org 207d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org // Previews & outlines 208eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org ArrayList<AppsCustomizeAsyncTask> mRunningTasks; 20941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org private static final int sPageSleepDelay = 200; 21043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 21143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private Runnable mInflateWidgetRunnable = null; 21243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private Runnable mBindWidgetRunnable = null; 213eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org static final int WIDGET_NO_CLEANUP_REQUIRED = -1; 214d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org static final int WIDGET_PRELOAD_PENDING = 0; 215d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org static final int WIDGET_BOUND = 1; 216eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org static final int WIDGET_INFLATED = 2; 21741044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED; 21843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int mWidgetLoadingId = -1; 21943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PendingAddWidgetInfo mCreateWidgetInfo = null; 22043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private boolean mDraggingWidget = false; 221eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 222d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org private Toast mWidgetInstructionToast; 223d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org 224eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org // Deferral of loading widget previews during launcher transitions 22541044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org private boolean mInTransition; 22643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private ArrayList<AsyncTaskPageData> mDeferredSyncWidgetPageItems = 22743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen new ArrayList<AsyncTaskPageData>(); 22843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks = 22943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen new ArrayList<Runnable>(); 23043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 23143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private Rect mTmpRect = new Rect(); 23243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 23343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Used for drawing shortcut previews 23443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); 235eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org PaintCache mCachedShortcutPreviewPaint = new PaintCache(); 236d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache(); 237d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org 238eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org // Used for drawing widget previews 23941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache(); 24043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen RectCache mCachedAppWidgetPreviewSrcRect = new RectCache(); 24143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen RectCache mCachedAppWidgetPreviewDestRect = new RectCache(); 24243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PaintCache mCachedAppWidgetPreviewPaint = new PaintCache(); 243eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 244eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org WidgetPreviewLoader mWidgetPreviewLoader; 245eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 246eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private boolean mInBulkBind; 247d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org private boolean mNeedToUpdatePageCountsAndInvalidateData; 248eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 249d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org public AppsCustomizePagedView(Context context, AttributeSet attrs) { 250eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org super(context, attrs); 251eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mLayoutInflater = LayoutInflater.from(context); 252eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mPackageManager = context.getPackageManager(); 253eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mApps = new ArrayList<ApplicationInfo>(); 254d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org mWidgets = new ArrayList<Object>(); 255eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache(); 256eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mCanvas = new Canvas(); 257eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>(); 258eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 259eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org // Save the default widget preview background 260eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0); 26141044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org mMaxAppCellCountX = a.getInt(R.styleable.AppsCustomizePagedView_maxAppCellCountX, -1); 26243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mMaxAppCellCountY = a.getInt(R.styleable.AppsCustomizePagedView_maxAppCellCountY, -1); 26343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetWidthGap = 26443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellWidthGap, 0); 265eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mWidgetHeightGap = 266d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellHeightGap, 0); 267d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2); 268eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2); 26941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org mClingFocusedX = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedX, 0); 27043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mClingFocusedY = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedY, 0); 27143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen a.recycle(); 27243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetSpacingLayout = new PagedViewCellLayout(getContext()); 273eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 274d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org // The padding on the non-matched dimension for the default widget preview icons 275d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org // (top + bottom) 276eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org mFadeInAdjacentScreens = false; 27741044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org 27843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Unless otherwise specified this view is important for accessibility. 27943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 28043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 281eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org } 282eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org } 283eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 284eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org @Override 285d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org protected void init() { 286eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org super.init(); 287d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org mCenterPagesVertically = false; 288eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 289eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org Context context = getContext(); 290eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org Resources r = context.getResources(); 291eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f); 292d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org } 293eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org 294eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org /** Returns the item index of the center item on this page so that we can restore to this 295eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org * item index when we rotate. */ 296eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org private int getMiddleComponentIndexOnCurrentPage() { 297eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org int i = -1; 298eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org if (getPageCount() > 0) { 29941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org int currentPage = getCurrentPage(); 30043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (currentPage < mNumAppsPages) { 30143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(currentPage); 30243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PagedViewCellLayoutChildren childrenLayout = layout.getChildrenLayout(); 303eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org int numItemsPerPage = mCellCountX * mCellCountY; 304d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org int childCount = childrenLayout.getChildCount(); 305d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org if (childCount > 0) { 306eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org i = (currentPage * numItemsPerPage) + (childCount / 2); 30741044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org } 30843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } else { 30943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int numApps = mApps.size(); 31043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage); 31143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int numItemsPerPage = mWidgetCountX * mWidgetCountY; 31243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int childCount = layout.getChildCount(); 31343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (childCount > 0) { 31443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen i = numApps + 31543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen ((currentPage - mNumAppsPages) * numItemsPerPage) + (childCount / 2); 31643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 31749edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.org } 318750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org } 31941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org return i; 32043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 32143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 32243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** Get the index of the item to restore to if we need to restore the current page. */ 32343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int getSaveInstanceStateIndex() { 3244980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org if (mSaveInstanceStateItemIndex == -1) { 32543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage(); 32643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 327c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com return mSaveInstanceStateItemIndex; 328750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org } 32941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org 33043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** Returns the page in the current orientation which is expected to contain the specified 33143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * item index. */ 3327c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org int getPageForComponent(int index) { 3338ccb0be15fd0cd7e7804e90fa1ebf302cb7fa44bkasperl@chromium.org if (index < 0) return 0; 3347c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org 3357c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org if (index < mApps.size()) { 33643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int numItemsPerPage = mCellCountX * mCellCountY; 33743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return (index / numItemsPerPage); 33834e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org } else { 339935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org int numItemsPerPage = mWidgetCountX * mWidgetCountY; 34043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return mNumAppsPages + ((index - mApps.size()) / numItemsPerPage); 34143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 34243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 3434980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org 3447c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org /** Restores the page for an item at the specified index */ 34543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen void restorePageForIndex(int index) { 34643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (index < 0) return; 347394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com mSaveInstanceStateItemIndex = index; 348394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com } 349394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com 350394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com private void updatePageCounts() { 351394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com mNumWidgetPages = (int) Math.ceil(mWidgets.size() / 352394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com (float) (mWidgetCountX * mWidgetCountY)); 35343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY)); 35443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 3554980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org 35643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen protected void onDataReady(int width, int height) { 35743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (mWidgetPreviewLoader == null) { 35843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetPreviewLoader = new WidgetPreviewLoader(mLauncher); 35943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 3607c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org 36141044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org // Note that we transpose the counts in portrait so that we get a similar layout 36243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen boolean isLandscape = getResources().getConfiguration().orientation == 36343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Configuration.ORIENTATION_LANDSCAPE; 36443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int maxCellCountX = Integer.MAX_VALUE; 36543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int maxCellCountY = Integer.MAX_VALUE; 366ea4f62e1df22417fc8dc2c2425485dca98b13d07ager@chromium.org if (LauncherApplication.isScreenLarge()) { 36743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen maxCellCountX = (isLandscape ? LauncherModel.getCellCountX() : 368750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org LauncherModel.getCellCountY()); 36943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen maxCellCountY = (isLandscape ? LauncherModel.getCellCountY() : 370ea4f62e1df22417fc8dc2c2425485dca98b13d07ager@chromium.org LauncherModel.getCellCountX()); 37141044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org } 37243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (mMaxAppCellCountX > -1) { 37343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen maxCellCountX = Math.min(maxCellCountX, mMaxAppCellCountX); 37443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 3755c838251403b0be9a882540f1922577abba4c872ager@chromium.org // Temp hack for now: only use the max cell count Y for widget layout 37643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int maxWidgetCellCountY = maxCellCountY; 3775c838251403b0be9a882540f1922577abba4c872ager@chromium.org if (mMaxAppCellCountY > -1) { 37843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen maxWidgetCellCountY = Math.min(maxWidgetCellCountY, mMaxAppCellCountY); 37934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org } 38005521fcc4bd495d3dc2b3ae7a6bc7e52ccb7937bsgjesse@chromium.org 38105521fcc4bd495d3dc2b3ae7a6bc7e52ccb7937bsgjesse@chromium.org // Now that the data is ready, we can calculate the content width, the number of cells to 38205521fcc4bd495d3dc2b3ae7a6bc7e52ccb7937bsgjesse@chromium.org // use for each page 38305521fcc4bd495d3dc2b3ae7a6bc7e52ccb7937bsgjesse@chromium.org mWidgetSpacingLayout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap); 3845c838251403b0be9a882540f1922577abba4c872ager@chromium.org mWidgetSpacingLayout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, 38505521fcc4bd495d3dc2b3ae7a6bc7e52ccb7937bsgjesse@chromium.org mPageLayoutPaddingRight, mPageLayoutPaddingBottom); 3865c838251403b0be9a882540f1922577abba4c872ager@chromium.org mWidgetSpacingLayout.calculateCellCount(width, height, maxCellCountX, maxCellCountY); 38705521fcc4bd495d3dc2b3ae7a6bc7e52ccb7937bsgjesse@chromium.org mCellCountX = mWidgetSpacingLayout.getCellCountX(); 38834e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org mCellCountY = mWidgetSpacingLayout.getCellCountY(); 38934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org updatePageCounts(); 39034e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org 39134e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org // Force a measure to update recalculate the gaps 39234e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); 39334e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST); 39434e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org mWidgetSpacingLayout.calculateCellCount(width, height, maxCellCountX, maxWidgetCellCountY); 39534e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org mWidgetSpacingLayout.measure(widthSpec, heightSpec); 39634e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org mContentWidth = mWidgetSpacingLayout.getContentWidth(); 39734e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org 39834e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org AppsCustomizeTabHost host = (AppsCustomizeTabHost) getTabHost(); 39934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org final boolean hostIsTransitioning = host.isTransitioning(); 400c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com 401c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com // Restore the page 40234e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org int page = getPageForComponent(mSaveInstanceStateItemIndex); 403c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com invalidatePageData(Math.max(0, page), hostIsTransitioning); 40441044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org 40543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Show All Apps cling if we are finished transitioning, otherwise, we will try again when 40643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // the transition completes in AppsCustomizeTabHost (otherwise the wrong offsets will be 40743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // returned while animating) 40843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (!hostIsTransitioning) { 4093e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org post(new Runnable() { 4103e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org @Override 4113e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org public void run() { 4122abc450936e88b5c98a5e9d43ee6230ccc748272kasperl@chromium.org showAllAppsCling(); 41343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 41434e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org }); 41534e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org } 41643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 41743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 41843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen void showAllAppsCling() { 41943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (!mHasShownAllAppsCling && isDataReady()) { 42043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mHasShownAllAppsCling = true; 42143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Calculate the position for the cling punch through 42243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] offset = new int[2]; 42343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] pos = mWidgetSpacingLayout.estimateCellPosition(mClingFocusedX, mClingFocusedY); 42443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mLauncher.getDragLayer().getLocationInDragLayer(this, offset); 42543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // PagedViews are centered horizontally but top aligned 4266a2b0aa331a1ae1829a9b9637ad18cfc7ec9d840ager@chromium.org // Note we have to shift the items up now that Launcher sits under the status bar 42743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen pos[0] += (getMeasuredWidth() - mWidgetSpacingLayout.getMeasuredWidth()) / 2 + 42843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen offset[0]; 42934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org pos[1] += offset[1] - mLauncher.getDragLayer().getPaddingTop(); 4301b3afd1cab9087ca3c4e585d3da77d374d65c082mstarzinger@chromium.org mLauncher.showFirstRunAllAppsCling(pos); 4311b3afd1cab9087ca3c4e585d3da77d374d65c082mstarzinger@chromium.org } 43243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 43343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 43443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen @Override 435394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int width = MeasureSpec.getSize(widthMeasureSpec); 43743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int height = MeasureSpec.getSize(heightMeasureSpec); 4389a4089a092cad9ff23b6416b92cd5d818dc101d1mads.s.ager@gmail.com if (!isDataReady()) { 43943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (mApps.size() > 0 && !mWidgets.isEmpty()) { 44043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen setDataIsReady(); 44143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen setMeasuredDimension(width, height); 44241044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org onDataReady(width, height); 44343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 44443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 445e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org 4466a2b0aa331a1ae1829a9b9637ad18cfc7ec9d840ager@chromium.org super.onMeasure(widthMeasureSpec, heightMeasureSpec); 44741044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org } 44843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 44943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) { 45043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Get the list of widgets and shortcuts 45143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgets.clear(); 45243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen for (Object o : widgetsAndShortcuts) { 45341044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org if (o instanceof AppWidgetProviderInfo) { 45443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen AppWidgetProviderInfo widget = (AppWidgetProviderInfo) o; 45543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (widget.minWidth > 0 && widget.minHeight > 0) { 45643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Ensure that all widgets we show can be added on a workspace of this size 45743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget); 45843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget); 45941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org int minSpanX = Math.min(spanXY[0], minSpanXY[0]); 46043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int minSpanY = Math.min(spanXY[1], minSpanXY[1]); 46143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (minSpanX <= LauncherModel.getCellCountX() && 46243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen minSpanY <= LauncherModel.getCellCountY()) { 46343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgets.add(widget); 46443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } else { 46541044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" + 46643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen widget.minWidth + ", " + widget.minHeight + ")"); 46743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 46843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } else { 46943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" + 47043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen widget.minWidth + ", " + widget.minHeight + ")"); 47143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 47243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } else { 47343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // just add shortcuts 47443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgets.add(o); 47543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 4767c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org } 4777c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org updatePageCountsAndInvalidateData(); 4787c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org } 4794980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org 480f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org public void setBulkBind(boolean bulkBind) { 48143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (bulkBind) { 48243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mInBulkBind = true; 48341044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org } else { 48443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mInBulkBind = false; 48543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (mNeedToUpdatePageCountsAndInvalidateData) { 4865c838251403b0be9a882540f1922577abba4c872ager@chromium.org updatePageCountsAndInvalidateData(); 4875c838251403b0be9a882540f1922577abba4c872ager@chromium.org } 4885c838251403b0be9a882540f1922577abba4c872ager@chromium.org } 4895c838251403b0be9a882540f1922577abba4c872ager@chromium.org } 4905c838251403b0be9a882540f1922577abba4c872ager@chromium.org 4915c838251403b0be9a882540f1922577abba4c872ager@chromium.org private void updatePageCountsAndInvalidateData() { 4925c838251403b0be9a882540f1922577abba4c872ager@chromium.org if (mInBulkBind) { 4935c838251403b0be9a882540f1922577abba4c872ager@chromium.org mNeedToUpdatePageCountsAndInvalidateData = true; 4945c838251403b0be9a882540f1922577abba4c872ager@chromium.org } else { 4955c838251403b0be9a882540f1922577abba4c872ager@chromium.org updatePageCounts(); 49643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen invalidateOnDataChange(); 49743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mNeedToUpdatePageCountsAndInvalidateData = false; 49843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 499d236f4d96b5dd21acc5ec57f4e50fa97cdd97bb6ricow@chromium.org } 500d236f4d96b5dd21acc5ec57f4e50fa97cdd97bb6ricow@chromium.org 501d236f4d96b5dd21acc5ec57f4e50fa97cdd97bb6ricow@chromium.org @Override 502d236f4d96b5dd21acc5ec57f4e50fa97cdd97bb6ricow@chromium.org public void onClick(View v) { 50343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // When we have exited all apps or are in transition, disregard clicks 504690083842e7c67a362017dae50909d4bb0b2a9c2mstarzinger@chromium.org if (!mLauncher.isAllAppsVisible() || 50531c0e32e19ad3df48525fa9e7b2d1c0c07496d00machenbach@chromium.org mLauncher.getWorkspace().isSwitchingState()) return; 50643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 50741044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org if (v instanceof PagedViewIcon) { 50843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Animate some feedback to the click 509d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org final ApplicationInfo appInfo = (ApplicationInfo) v.getTag(); 510d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org 511d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org // Lock the drawable state to pressed until we return to Launcher 512d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org if (mPressedIcon != null) { 513d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org mPressedIcon.lockDrawableState(); 514d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org } 515690083842e7c67a362017dae50909d4bb0b2a9c2mstarzinger@chromium.org 51631c0e32e19ad3df48525fa9e7b2d1c0c07496d00machenbach@chromium.org // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled 517d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org // to be consistent. So re-enable the flag here, and we will re-disable it as necessary 518d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org // when Launcher resumes and we are still in AllApps. 519d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org mLauncher.updateWallpaperVisibility(true); 52043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mLauncher.startActivitySafely(v, appInfo.intent, appInfo); 52143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 52243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } else if (v instanceof PagedViewWidget) { 52343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Let the user know that they have to long press to add a widget 5245c838251403b0be9a882540f1922577abba4c872ager@chromium.org if (mWidgetInstructionToast != null) { 52543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetInstructionToast.cancel(); 52643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 527f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, 52843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Toast.LENGTH_SHORT); 52941044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org mWidgetInstructionToast.show(); 53043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 531b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org // Create a little animation to show that the widget can move 532357bf65ed5309ac3a2c4bf20b6ce7770488787c2ager@chromium.org float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); 533b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); 534b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); 535f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); 536b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org tyuAnim.setDuration(125); 537b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); 538b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org tydAnim.setDuration(100); 53943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen bounce.play(tyuAnim).before(tydAnim); 540750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org bounce.setInterpolator(new AccelerateInterpolator()); 541750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org bounce.start(); 542750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org } 543750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org } 544750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org 545750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org public boolean onKey(View v, int keyCode, KeyEvent event) { 54643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return FocusHelper.handleAppsCustomizeKeyEvent(v, keyCode, event); 54743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 54843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 54943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /* 55043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * PagedViewWithDraggableItems implementation 551f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org */ 552b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org @Override 553e0e1b0d3e70c933d36ed381d511e9fda39f2a751mstarzinger@chromium.org protected void determineDraggingStart(android.view.MotionEvent ev) { 554b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org // Disable dragging by pulling an app down for now. 55543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 55641044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org 55743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private void beginDraggingApplication(View v) { 55843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mLauncher.getWorkspace().onDragStartedWithItem(v); 55943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mLauncher.getWorkspace().beginDragShared(v, this); 56043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 56143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 56243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { 56341044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org Bundle options = null; 56443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 56543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, mTmpRect); 566a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(mLauncher, 567a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org info.componentName, null); 568a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org 569a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org float density = getResources().getDisplayMetrics().density; 570a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org int xPaddingDips = (int) ((padding.left + padding.right) / density); 571a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org int yPaddingDips = (int) ((padding.top + padding.bottom) / density); 572a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org 573a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org options = new Bundle(); 57443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 57543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mTmpRect.left - xPaddingDips); 576769cc962a043dd8d92cc010dd2c50bc26f652c94mads.s.ager@gmail.com options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 57743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mTmpRect.top - yPaddingDips); 57841044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 57943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mTmpRect.right - xPaddingDips); 58043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 58143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mTmpRect.bottom - yPaddingDips); 58243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 58343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return options; 58443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 58541044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org 58643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private void preloadWidget(final PendingAddWidgetInfo info) { 58743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen final AppWidgetProviderInfo pInfo = info.info; 5885c838251403b0be9a882540f1922577abba4c872ager@chromium.org final Bundle options = getDefaultOptionsForWidget(mLauncher, info); 5895c838251403b0be9a882540f1922577abba4c872ager@chromium.org 5905c838251403b0be9a882540f1922577abba4c872ager@chromium.org if (pInfo.configure != null) { 5915c838251403b0be9a882540f1922577abba4c872ager@chromium.org info.bindOptions = options; 5925c838251403b0be9a882540f1922577abba4c872ager@chromium.org return; 5939155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org } 5940cc095007a3ccded63f6577751c6a04300eb7ae9machenbach@chromium.org 5950cc095007a3ccded63f6577751c6a04300eb7ae9machenbach@chromium.org mWidgetCleanupState = WIDGET_PRELOAD_PENDING; 5960cc095007a3ccded63f6577751c6a04300eb7ae9machenbach@chromium.org mBindWidgetRunnable = new Runnable() { 5975c838251403b0be9a882540f1922577abba4c872ager@chromium.org @Override 598d2c22f0121ebc55ee26a9e742f0fd7c0b8397730kmillikin@chromium.org public void run() { 5995c838251403b0be9a882540f1922577abba4c872ager@chromium.org mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); 6005c838251403b0be9a882540f1922577abba4c872ager@chromium.org if (AppWidgetManager.getInstance(mLauncher).bindAppWidgetIdIfAllowed( 60143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetLoadingId, info.info.getProfile(), info.componentName, options)) { 60243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetCleanupState = WIDGET_BOUND; 60343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 60443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 60543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen }; 60643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen post(mBindWidgetRunnable); 60743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 60843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mInflateWidgetRunnable = new Runnable() { 60943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen @Override 6104980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org public void run() { 6114980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org if (mWidgetCleanupState != WIDGET_BOUND) { 6124980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org return; 6134980dff4208f9b77bc5320af43d7cc4b2a3d9688ricow@chromium.org } 61441044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org AppWidgetHostView hostView = mLauncher. 61543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen getAppWidgetHost().createView(getContext(), mWidgetLoadingId, pInfo); 61643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen info.boundWidget = hostView; 61743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mWidgetCleanupState = WIDGET_INFLATED; 61843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen hostView.setVisibility(INVISIBLE); 6194c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info.spanX, 6204c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org info.spanY, info, false); 6214c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org 6224c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org // We want the first widget layout to be the correct size. This will be important 6234c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org // for width size reporting to the AppWidgetManager. 6244c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0], 62543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen unScaledSize[1]); 6264c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org lp.x = lp.y = 0; 6274c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org lp.customPosition = true; 6284c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org hostView.setLayoutParams(lp); 6294c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org mLauncher.getDragLayer().addView(hostView); 6304c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org } 63143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen }; 63243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen post(mInflateWidgetRunnable); 63341044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org } 63443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 63543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen @Override 63643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public void onShortPress(View v) { 6374c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org // We are anticipating a long press, and we use this time to load bind and instantiate 6384c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org // the widget. This will need to be cleaned up if it turns out no long press occurs. 6394c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org if (mCreateWidgetInfo != null) { 6404c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org // Just in case the cleanup process wasn't properly executed. This shouldn't happen. 6414c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org cleanupWidgetPreloading(false); 6424c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org } 64343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag()); 6444c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org preloadWidget(mCreateWidgetInfo); 6454c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org } 6464c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org 6474c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org private void cleanupWidgetPreloading(boolean widgetWasAdded) { 6484c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org if (!widgetWasAdded) { 64943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // If the widget was not added, we may need to do further cleanup. 65043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen PendingAddWidgetInfo info = mCreateWidgetInfo; 65141044eb0969b0d7d5c041a077519a36efa6aff27kasperl@chromium.org mCreateWidgetInfo = null; 65243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 6531510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) { 6541510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org // We never did any preloading, so just remove pending callbacks to do so 655af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org removeCallbacks(mBindWidgetRunnable); 6561510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org removeCallbacks(mInflateWidgetRunnable); 6571510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org } else if (mWidgetCleanupState == WIDGET_BOUND) { 6581510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org // Delete the widget id which was allocated 65943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (mWidgetLoadingId != -1) { 66043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); 66143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 66243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 6637304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org // We never got around to inflating the widget, so remove the callback to do so. 66443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen removeCallbacks(mInflateWidgetRunnable); 66543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } else if (mWidgetCleanupState == WIDGET_INFLATED) { 666 // Delete the widget id which was allocated 667 if (mWidgetLoadingId != -1) { 668 mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); 669 } 670 671 // The widget was inflated and added to the DragLayer -- remove it. 672 AppWidgetHostView widget = info.boundWidget; 673 mLauncher.getDragLayer().removeView(widget); 674 } 675 } 676 mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED; 677 mWidgetLoadingId = -1; 678 mCreateWidgetInfo = null; 679 PagedViewWidget.resetShortPressTarget(); 680 } 681 682 @Override 683 public void cleanUpShortPress(View v) { 684 if (!mDraggingWidget) { 685 cleanupWidgetPreloading(false); 686 } 687 } 688 689 private boolean beginDraggingWidget(View v) { 690 mDraggingWidget = true; 691 // Get the widget preview as the drag representation 692 ImageView image = (ImageView) v.findViewById(R.id.widget_preview); 693 PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag(); 694 695 // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and 696 // we abort the drag. 697 if (image.getDrawable() == null) { 698 mDraggingWidget = false; 699 return false; 700 } 701 702 // Compose the drag image 703 Bitmap preview; 704 Bitmap outline; 705 float scale = 1f; 706 Point previewPadding = null; 707 708 if (createItemInfo instanceof PendingAddWidgetInfo) { 709 // This can happen in some weird cases involving multi-touch. We can't start dragging 710 // the widget if this is null, so we break out. 711 if (mCreateWidgetInfo == null) { 712 return false; 713 } 714 715 PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo; 716 createItemInfo = createWidgetInfo; 717 int spanX = createItemInfo.spanX; 718 int spanY = createItemInfo.spanY; 719 int[] size = mLauncher.getWorkspace().estimateItemSize(spanX, spanY, 720 createWidgetInfo, true); 721 722 FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable(); 723 float minScale = 1.25f; 724 int maxWidth, maxHeight; 725 maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]); 726 maxHeight = Math.min((int) (previewDrawable.getIntrinsicHeight() * minScale), size[1]); 727 728 int[] previewSizeBeforeScale = new int[1]; 729 730 preview = mWidgetPreviewLoader.generateWidgetPreview(createWidgetInfo.info, spanX, 731 spanY, maxWidth, maxHeight, null, previewSizeBeforeScale); 732 733 // Compare the size of the drag preview to the preview in the AppsCustomize tray 734 int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0], 735 mWidgetPreviewLoader.maxWidthForWidgetPreview(spanX)); 736 scale = previewWidthInAppsCustomize / (float) preview.getWidth(); 737 738 // The bitmap in the AppsCustomize tray is always the the same size, so there 739 // might be extra pixels around the preview itself - this accounts for that 740 if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) { 741 int padding = 742 (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2; 743 previewPadding = new Point(padding, 0); 744 } 745 } else { 746 PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag(); 747 // Widgets are only supported for current user, not for other profiles. 748 // Hence use myUserHandle(). 749 Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo, 750 android.os.Process.myUserHandle()); 751 preview = Bitmap.createBitmap(icon.getIntrinsicWidth(), 752 icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 753 754 mCanvas.setBitmap(preview); 755 mCanvas.save(); 756 WidgetPreviewLoader.renderDrawableToBitmap(icon, preview, 0, 0, 757 icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); 758 mCanvas.restore(); 759 mCanvas.setBitmap(null); 760 createItemInfo.spanX = createItemInfo.spanY = 1; 761 } 762 763 // Don't clip alpha values for the drag outline if we're using the default widget preview 764 boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo && 765 (((PendingAddWidgetInfo) createItemInfo).info.previewImage == 0)); 766 767 // Save the preview for the outline generation, then dim the preview 768 outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(), 769 false); 770 771 // Start the drag 772 mLauncher.lockScreenOrientation(); 773 mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha); 774 mDragController.startDrag(image, preview, this, createItemInfo, 775 DragController.DRAG_ACTION_COPY, previewPadding, scale); 776 outline.recycle(); 777 preview.recycle(); 778 return true; 779 } 780 781 @Override 782 protected boolean beginDragging(final View v) { 783 if (!super.beginDragging(v)) return false; 784 785 if (v instanceof PagedViewIcon) { 786 beginDraggingApplication(v); 787 } else if (v instanceof PagedViewWidget) { 788 if (!beginDraggingWidget(v)) { 789 return false; 790 } 791 } 792 793 // We delay entering spring-loaded mode slightly to make sure the UI 794 // thready is free of any work. 795 postDelayed(new Runnable() { 796 @Override 797 public void run() { 798 // We don't enter spring-loaded mode if the drag has been cancelled 799 if (mLauncher.getDragController().isDragging()) { 800 // Dismiss the cling 801 mLauncher.dismissAllAppsCling(null); 802 803 // Reset the alpha on the dragged icon before we drag 804 resetDrawableState(); 805 806 // Go into spring loaded mode (must happen before we startDrag()) 807 mLauncher.enterSpringLoadedDragMode(); 808 } 809 } 810 }, 150); 811 812 return true; 813 } 814 815 /** 816 * Clean up after dragging. 817 * 818 * @param target where the item was dragged to (can be null if the item was flung) 819 */ 820 private void endDragging(View target, boolean isFlingToDelete, boolean success) { 821 if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && 822 !(target instanceof DeleteDropTarget))) { 823 // Exit spring loaded mode if we have not successfully dropped or have not handled the 824 // drop in Workspace 825 mLauncher.exitSpringLoadedDragMode(); 826 } 827 mLauncher.unlockScreenOrientation(false); 828 } 829 830 @Override 831 public View getContent() { 832 return null; 833 } 834 835 @Override 836 public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) { 837 mInTransition = true; 838 if (toWorkspace) { 839 cancelAllTasks(); 840 } 841 } 842 843 @Override 844 public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) { 845 } 846 847 @Override 848 public void onLauncherTransitionStep(Launcher l, float t) { 849 } 850 851 @Override 852 public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { 853 mInTransition = false; 854 for (AsyncTaskPageData d : mDeferredSyncWidgetPageItems) { 855 onSyncWidgetPageItems(d); 856 } 857 mDeferredSyncWidgetPageItems.clear(); 858 for (Runnable r : mDeferredPrepareLoadWidgetPreviewsTasks) { 859 r.run(); 860 } 861 mDeferredPrepareLoadWidgetPreviewsTasks.clear(); 862 mForceDrawAllChildrenNextFrame = !toWorkspace; 863 } 864 865 @Override 866 public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, 867 boolean success) { 868 // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling 869 if (isFlingToDelete) return; 870 871 endDragging(target, false, success); 872 873 // Display an error message if the drag failed due to there not being enough space on the 874 // target layout we were dropping on. 875 if (!success) { 876 boolean showOutOfSpaceMessage = false; 877 if (target instanceof Workspace) { 878 int currentScreen = mLauncher.getCurrentWorkspaceScreen(); 879 Workspace workspace = (Workspace) target; 880 CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen); 881 ItemInfo itemInfo = (ItemInfo) d.dragInfo; 882 if (layout != null) { 883 layout.calculateSpans(itemInfo); 884 showOutOfSpaceMessage = 885 !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY); 886 } 887 } 888 if (showOutOfSpaceMessage) { 889 mLauncher.showOutOfSpaceMessage(false); 890 } 891 892 d.deferDragViewCleanupPostAnimation = false; 893 } 894 cleanupWidgetPreloading(success); 895 mDraggingWidget = false; 896 } 897 898 @Override 899 public void onFlingToDeleteCompleted() { 900 // We just dismiss the drag when we fling, so cleanup here 901 endDragging(null, true, true); 902 cleanupWidgetPreloading(false); 903 mDraggingWidget = false; 904 } 905 906 @Override 907 public boolean supportsFlingToDelete() { 908 return true; 909 } 910 911 @Override 912 protected void onDetachedFromWindow() { 913 super.onDetachedFromWindow(); 914 cancelAllTasks(); 915 } 916 917 public void clearAllWidgetPages() { 918 cancelAllTasks(); 919 int count = getChildCount(); 920 for (int i = 0; i < count; i++) { 921 View v = getPageAt(i); 922 if (v instanceof PagedViewGridLayout) { 923 ((PagedViewGridLayout) v).removeAllViewsOnPage(); 924 mDirtyPageContent.set(i, true); 925 } 926 } 927 } 928 929 private void cancelAllTasks() { 930 // Clean up all the async tasks 931 Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); 932 while (iter.hasNext()) { 933 AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); 934 task.cancel(false); 935 iter.remove(); 936 mDirtyPageContent.set(task.page, true); 937 938 // We've already preallocated the views for the data to load into, so clear them as well 939 View v = getPageAt(task.page); 940 if (v instanceof PagedViewGridLayout) { 941 ((PagedViewGridLayout) v).removeAllViewsOnPage(); 942 } 943 } 944 mDeferredSyncWidgetPageItems.clear(); 945 mDeferredPrepareLoadWidgetPreviewsTasks.clear(); 946 } 947 948 public void setContentType(ContentType type) { 949 if (type == ContentType.Widgets) { 950 invalidatePageData(mNumAppsPages, true); 951 } else if (type == ContentType.Applications) { 952 invalidatePageData(0, true); 953 } 954 } 955 956 protected void snapToPage(int whichPage, int delta, int duration) { 957 super.snapToPage(whichPage, delta, duration); 958 updateCurrentTab(whichPage); 959 960 // Update the thread priorities given the direction lookahead 961 Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); 962 while (iter.hasNext()) { 963 AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); 964 int pageIndex = task.page; 965 if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) || 966 (mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) { 967 task.setThreadPriority(getThreadPriorityForPage(pageIndex)); 968 } else { 969 task.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); 970 } 971 } 972 } 973 974 private void updateCurrentTab(int currentPage) { 975 AppsCustomizeTabHost tabHost = getTabHost(); 976 if (tabHost != null) { 977 String tag = tabHost.getCurrentTabTag(); 978 if (tag != null) { 979 if (currentPage >= mNumAppsPages && 980 !tag.equals(tabHost.getTabTagForContentType(ContentType.Widgets))) { 981 tabHost.setCurrentTabFromContent(ContentType.Widgets); 982 } else if (currentPage < mNumAppsPages && 983 !tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) { 984 tabHost.setCurrentTabFromContent(ContentType.Applications); 985 } 986 } 987 } 988 } 989 990 /* 991 * Apps PagedView implementation 992 */ 993 private void setVisibilityOnChildren(ViewGroup layout, int visibility) { 994 int childCount = layout.getChildCount(); 995 for (int i = 0; i < childCount; ++i) { 996 layout.getChildAt(i).setVisibility(visibility); 997 } 998 } 999 private void setupPage(PagedViewCellLayout layout) { 1000 layout.setCellCount(mCellCountX, mCellCountY); 1001 layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap); 1002 layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, 1003 mPageLayoutPaddingRight, mPageLayoutPaddingBottom); 1004 1005 // Note: We force a measure here to get around the fact that when we do layout calculations 1006 // immediately after syncing, we don't have a proper width. That said, we already know the 1007 // expected page width, so we can actually optimize by hiding all the TextView-based 1008 // children that are expensive to measure, and let that happen naturally later. 1009 setVisibilityOnChildren(layout, View.GONE); 1010 int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); 1011 int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST); 1012 layout.setMinimumWidth(getPageContentWidth()); 1013 layout.measure(widthSpec, heightSpec); 1014 setVisibilityOnChildren(layout, View.VISIBLE); 1015 } 1016 1017 public void syncAppsPageItems(int page, boolean immediate) { 1018 // ensure that we have the right number of items on the pages 1019 final boolean isRtl = isLayoutRtl(); 1020 int numCells = mCellCountX * mCellCountY; 1021 int startIndex = page * numCells; 1022 int endIndex = Math.min(startIndex + numCells, mApps.size()); 1023 PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(page); 1024 1025 layout.removeAllViewsOnPage(); 1026 ArrayList<Object> items = new ArrayList<Object>(); 1027 ArrayList<Bitmap> images = new ArrayList<Bitmap>(); 1028 for (int i = startIndex; i < endIndex; ++i) { 1029 ApplicationInfo info = mApps.get(i); 1030 PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( 1031 R.layout.apps_customize_application, layout, false); 1032 icon.applyFromApplicationInfo(info, true, this); 1033 icon.setOnClickListener(this); 1034 icon.setOnLongClickListener(this); 1035 icon.setOnTouchListener(this); 1036 icon.setOnKeyListener(this); 1037 1038 int index = i - startIndex; 1039 int x = index % mCellCountX; 1040 int y = index / mCellCountX; 1041 if (isRtl) { 1042 x = mCellCountX - x - 1; 1043 } 1044 layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1)); 1045 1046 items.add(info); 1047 images.add(info.iconBitmap); 1048 } 1049 1050 enableHwLayersOnVisiblePages(); 1051 } 1052 1053 /** 1054 * A helper to return the priority for loading of the specified widget page. 1055 */ 1056 private int getWidgetPageLoadPriority(int page) { 1057 // If we are snapping to another page, use that index as the target page index 1058 int toPage = mCurrentPage; 1059 if (mNextPage > -1) { 1060 toPage = mNextPage; 1061 } 1062 1063 // We use the distance from the target page as an initial guess of priority, but if there 1064 // are no pages of higher priority than the page specified, then bump up the priority of 1065 // the specified page. 1066 Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); 1067 int minPageDiff = Integer.MAX_VALUE; 1068 while (iter.hasNext()) { 1069 AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); 1070 minPageDiff = Math.abs(task.page - toPage); 1071 } 1072 1073 int rawPageDiff = Math.abs(page - toPage); 1074 return rawPageDiff - Math.min(rawPageDiff, minPageDiff); 1075 } 1076 /** 1077 * Return the appropriate thread priority for loading for a given page (we give the current 1078 * page much higher priority) 1079 */ 1080 private int getThreadPriorityForPage(int page) { 1081 // TODO-APPS_CUSTOMIZE: detect number of cores and set thread priorities accordingly below 1082 int pageDiff = getWidgetPageLoadPriority(page); 1083 if (pageDiff <= 0) { 1084 return Process.THREAD_PRIORITY_LESS_FAVORABLE; 1085 } else if (pageDiff <= 1) { 1086 return Process.THREAD_PRIORITY_LOWEST; 1087 } else { 1088 return Process.THREAD_PRIORITY_LOWEST; 1089 } 1090 } 1091 private int getSleepForPage(int page) { 1092 int pageDiff = getWidgetPageLoadPriority(page); 1093 return Math.max(0, pageDiff * sPageSleepDelay); 1094 } 1095 /** 1096 * Creates and executes a new AsyncTask to load a page of widget previews. 1097 */ 1098 private void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets, 1099 int cellWidth, int cellHeight, int cellCountX) { 1100 1101 // Prune all tasks that are no longer needed 1102 Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); 1103 while (iter.hasNext()) { 1104 AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); 1105 int taskPage = task.page; 1106 if (taskPage < getAssociatedLowerPageBound(mCurrentPage) || 1107 taskPage > getAssociatedUpperPageBound(mCurrentPage)) { 1108 task.cancel(false); 1109 iter.remove(); 1110 } else { 1111 task.setThreadPriority(getThreadPriorityForPage(taskPage)); 1112 } 1113 } 1114 1115 // We introduce a slight delay to order the loading of side pages so that we don't thrash 1116 final int sleepMs = getSleepForPage(page); 1117 AsyncTaskPageData pageData = new AsyncTaskPageData(page, widgets, cellWidth, cellHeight, 1118 new AsyncTaskCallback() { 1119 @Override 1120 public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) { 1121 try { 1122 try { 1123 Thread.sleep(sleepMs); 1124 } catch (Exception e) {} 1125 loadWidgetPreviewsInBackground(task, data); 1126 } finally { 1127 if (task.isCancelled()) { 1128 data.cleanup(true); 1129 } 1130 } 1131 } 1132 }, 1133 new AsyncTaskCallback() { 1134 @Override 1135 public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) { 1136 mRunningTasks.remove(task); 1137 if (task.isCancelled()) return; 1138 // do cleanup inside onSyncWidgetPageItems 1139 onSyncWidgetPageItems(data); 1140 } 1141 }, mWidgetPreviewLoader); 1142 1143 // Ensure that the task is appropriately prioritized and runs in parallel 1144 AppsCustomizeAsyncTask t = new AppsCustomizeAsyncTask(page, 1145 AsyncTaskPageData.Type.LoadWidgetPreviewData); 1146 t.setThreadPriority(getThreadPriorityForPage(page)); 1147 t.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pageData); 1148 mRunningTasks.add(t); 1149 } 1150 1151 /* 1152 * Widgets PagedView implementation 1153 */ 1154 private void setupPage(PagedViewGridLayout layout) { 1155 layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, 1156 mPageLayoutPaddingRight, mPageLayoutPaddingBottom); 1157 1158 // Note: We force a measure here to get around the fact that when we do layout calculations 1159 // immediately after syncing, we don't have a proper width. 1160 int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); 1161 int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST); 1162 layout.setMinimumWidth(getPageContentWidth()); 1163 layout.measure(widthSpec, heightSpec); 1164 } 1165 1166 public void syncWidgetPageItems(final int page, final boolean immediate) { 1167 int numItemsPerPage = mWidgetCountX * mWidgetCountY; 1168 1169 // Calculate the dimensions of each cell we are giving to each widget 1170 final ArrayList<Object> items = new ArrayList<Object>(); 1171 int contentWidth = mWidgetSpacingLayout.getContentWidth(); 1172 final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft - mPageLayoutPaddingRight 1173 - ((mWidgetCountX - 1) * mWidgetWidthGap)) / mWidgetCountX); 1174 int contentHeight = mWidgetSpacingLayout.getContentHeight(); 1175 final int cellHeight = ((contentHeight - mPageLayoutPaddingTop - mPageLayoutPaddingBottom 1176 - ((mWidgetCountY - 1) * mWidgetHeightGap)) / mWidgetCountY); 1177 1178 // Prepare the set of widgets to load previews for in the background 1179 int offset = (page - mNumAppsPages) * numItemsPerPage; 1180 for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) { 1181 items.add(mWidgets.get(i)); 1182 } 1183 1184 // Prepopulate the pages with the other widget info, and fill in the previews later 1185 final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); 1186 layout.setColumnCount(layout.getCellCountX()); 1187 for (int i = 0; i < items.size(); ++i) { 1188 Object rawInfo = items.get(i); 1189 PendingAddItemInfo createItemInfo = null; 1190 PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate( 1191 R.layout.apps_customize_widget, layout, false); 1192 if (rawInfo instanceof AppWidgetProviderInfo) { 1193 // Fill in the widget information 1194 AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo; 1195 createItemInfo = new PendingAddWidgetInfo(info, null, null); 1196 1197 // Determine the widget spans and min resize spans. 1198 int[] spanXY = Launcher.getSpanForWidget(mLauncher, info); 1199 createItemInfo.spanX = spanXY[0]; 1200 createItemInfo.spanY = spanXY[1]; 1201 int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, info); 1202 createItemInfo.minSpanX = minSpanXY[0]; 1203 createItemInfo.minSpanY = minSpanXY[1]; 1204 1205 widget.applyFromAppWidgetProviderInfo(info, -1, spanXY, mWidgetPreviewLoader); 1206 widget.setTag(createItemInfo); 1207 widget.setShortPressListener(this); 1208 } else if (rawInfo instanceof ResolveInfo) { 1209 // Fill in the shortcuts information 1210 ResolveInfo info = (ResolveInfo) rawInfo; 1211 createItemInfo = new PendingAddShortcutInfo(info.activityInfo); 1212 createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; 1213 createItemInfo.componentName = new ComponentName(info.activityInfo.packageName, 1214 info.activityInfo.name); 1215 widget.applyFromResolveInfo(mPackageManager, info, mWidgetPreviewLoader); 1216 widget.setTag(createItemInfo); 1217 } 1218 widget.setOnClickListener(this); 1219 widget.setOnLongClickListener(this); 1220 widget.setOnTouchListener(this); 1221 widget.setOnKeyListener(this); 1222 1223 // Layout each widget 1224 int ix = i % mWidgetCountX; 1225 int iy = i / mWidgetCountX; 1226 GridLayout.LayoutParams lp = new GridLayout.LayoutParams( 1227 GridLayout.spec(iy, GridLayout.START), 1228 GridLayout.spec(ix, GridLayout.TOP)); 1229 lp.width = cellWidth; 1230 lp.height = cellHeight; 1231 lp.setGravity(Gravity.TOP | Gravity.START); 1232 if (ix > 0) lp.leftMargin = mWidgetWidthGap; 1233 if (iy > 0) lp.topMargin = mWidgetHeightGap; 1234 layout.addView(widget, lp); 1235 } 1236 1237 // wait until a call on onLayout to start loading, because 1238 // PagedViewWidget.getPreviewSize() will return 0 if it hasn't been laid out 1239 // TODO: can we do a measure/layout immediately? 1240 layout.setOnLayoutListener(new Runnable() { 1241 public void run() { 1242 // Load the widget previews 1243 int maxPreviewWidth = cellWidth; 1244 int maxPreviewHeight = cellHeight; 1245 if (layout.getChildCount() > 0) { 1246 PagedViewWidget w = (PagedViewWidget) layout.getChildAt(0); 1247 int[] maxSize = w.getPreviewSize(); 1248 maxPreviewWidth = maxSize[0]; 1249 maxPreviewHeight = maxSize[1]; 1250 } 1251 1252 mWidgetPreviewLoader.setPreviewSize( 1253 maxPreviewWidth, maxPreviewHeight, mWidgetSpacingLayout); 1254 if (immediate) { 1255 AsyncTaskPageData data = new AsyncTaskPageData(page, items, 1256 maxPreviewWidth, maxPreviewHeight, null, null, mWidgetPreviewLoader); 1257 loadWidgetPreviewsInBackground(null, data); 1258 onSyncWidgetPageItems(data); 1259 } else { 1260 if (mInTransition) { 1261 mDeferredPrepareLoadWidgetPreviewsTasks.add(this); 1262 } else { 1263 prepareLoadWidgetPreviewsTask(page, items, 1264 maxPreviewWidth, maxPreviewHeight, mWidgetCountX); 1265 } 1266 } 1267 layout.setOnLayoutListener(null); 1268 } 1269 }); 1270 } 1271 private void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task, 1272 AsyncTaskPageData data) { 1273 // loadWidgetPreviewsInBackground can be called without a task to load a set of widget 1274 // previews synchronously 1275 if (task != null) { 1276 // Ensure that this task starts running at the correct priority 1277 task.syncThreadPriority(); 1278 } 1279 1280 // Load each of the widget/shortcut previews 1281 ArrayList<Object> items = data.items; 1282 ArrayList<Bitmap> images = data.generatedImages; 1283 int count = items.size(); 1284 for (int i = 0; i < count; ++i) { 1285 if (task != null) { 1286 // Ensure we haven't been cancelled yet 1287 if (task.isCancelled()) break; 1288 // Before work on each item, ensure that this task is running at the correct 1289 // priority 1290 task.syncThreadPriority(); 1291 } 1292 1293 images.add(mWidgetPreviewLoader.getPreview(items.get(i))); 1294 } 1295 } 1296 1297 private void onSyncWidgetPageItems(AsyncTaskPageData data) { 1298 if (mInTransition) { 1299 mDeferredSyncWidgetPageItems.add(data); 1300 return; 1301 } 1302 try { 1303 int page = data.page; 1304 PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); 1305 1306 ArrayList<Object> items = data.items; 1307 int count = items.size(); 1308 for (int i = 0; i < count; ++i) { 1309 PagedViewWidget widget = (PagedViewWidget) layout.getChildAt(i); 1310 if (widget != null) { 1311 Bitmap preview = data.generatedImages.get(i); 1312 widget.applyPreview(new FastBitmapDrawable(preview), i); 1313 } 1314 } 1315 1316 enableHwLayersOnVisiblePages(); 1317 1318 // Update all thread priorities 1319 Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); 1320 while (iter.hasNext()) { 1321 AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); 1322 int pageIndex = task.page; 1323 task.setThreadPriority(getThreadPriorityForPage(pageIndex)); 1324 } 1325 } finally { 1326 data.cleanup(false); 1327 } 1328 } 1329 1330 @Override 1331 public void syncPages() { 1332 removeAllViews(); 1333 cancelAllTasks(); 1334 1335 Context context = getContext(); 1336 for (int j = 0; j < mNumWidgetPages; ++j) { 1337 PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX, 1338 mWidgetCountY); 1339 setupPage(layout); 1340 addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT, 1341 LayoutParams.MATCH_PARENT)); 1342 } 1343 1344 for (int i = 0; i < mNumAppsPages; ++i) { 1345 PagedViewCellLayout layout = new PagedViewCellLayout(context); 1346 setupPage(layout); 1347 addView(layout); 1348 } 1349 } 1350 1351 @Override 1352 public void syncPageItems(int page, boolean immediate) { 1353 if (page < mNumAppsPages) { 1354 syncAppsPageItems(page, immediate); 1355 } else { 1356 syncWidgetPageItems(page, immediate); 1357 } 1358 } 1359 1360 // We want our pages to be z-ordered such that the further a page is to the left, the higher 1361 // it is in the z-order. This is important to insure touch events are handled correctly. 1362 View getPageAt(int index) { 1363 return getChildAt(indexToPage(index)); 1364 } 1365 1366 @Override 1367 protected int indexToPage(int index) { 1368 return getChildCount() - index - 1; 1369 } 1370 1371 // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack. 1372 @Override 1373 protected void screenScrolled(int screenCenter) { 1374 final boolean isRtl = isLayoutRtl(); 1375 super.screenScrolled(screenCenter); 1376 1377 for (int i = 0; i < getChildCount(); i++) { 1378 View v = getPageAt(i); 1379 if (v != null) { 1380 float scrollProgress = getScrollProgress(screenCenter, v, i); 1381 1382 float interpolatedProgress; 1383 float translationX; 1384 float maxScrollProgress = Math.max(0, scrollProgress); 1385 float minScrollProgress = Math.min(0, scrollProgress); 1386 1387 if (isRtl) { 1388 translationX = maxScrollProgress * v.getMeasuredWidth(); 1389 interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(maxScrollProgress)); 1390 } else { 1391 translationX = minScrollProgress * v.getMeasuredWidth(); 1392 interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress)); 1393 } 1394 float scale = (1 - interpolatedProgress) + 1395 interpolatedProgress * TRANSITION_SCALE_FACTOR; 1396 1397 float alpha; 1398 if (isRtl && (scrollProgress > 0)) { 1399 alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(maxScrollProgress)); 1400 } else if (!isRtl && (scrollProgress < 0)) { 1401 alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress)); 1402 } else { 1403 // On large screens we need to fade the page as it nears its leftmost position 1404 alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress); 1405 } 1406 1407 v.setCameraDistance(mDensity * CAMERA_DISTANCE); 1408 int pageWidth = v.getMeasuredWidth(); 1409 int pageHeight = v.getMeasuredHeight(); 1410 1411 if (PERFORM_OVERSCROLL_ROTATION) { 1412 float xPivot = isRtl ? 1f - TRANSITION_PIVOT : TRANSITION_PIVOT; 1413 boolean isOverscrollingFirstPage = isRtl ? scrollProgress > 0 : scrollProgress < 0; 1414 boolean isOverscrollingLastPage = isRtl ? scrollProgress < 0 : scrollProgress > 0; 1415 1416 if (i == 0 && isOverscrollingFirstPage) { 1417 // Overscroll to the left 1418 v.setPivotX(xPivot * pageWidth); 1419 v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress); 1420 scale = 1.0f; 1421 alpha = 1.0f; 1422 // On the first page, we don't want the page to have any lateral motion 1423 translationX = 0; 1424 } else if (i == getChildCount() - 1 && isOverscrollingLastPage) { 1425 // Overscroll to the right 1426 v.setPivotX((1 - xPivot) * pageWidth); 1427 v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress); 1428 scale = 1.0f; 1429 alpha = 1.0f; 1430 // On the last page, we don't want the page to have any lateral motion. 1431 translationX = 0; 1432 } else { 1433 v.setPivotY(pageHeight / 2.0f); 1434 v.setPivotX(pageWidth / 2.0f); 1435 v.setRotationY(0f); 1436 } 1437 } 1438 1439 v.setTranslationX(translationX); 1440 v.setScaleX(scale); 1441 v.setScaleY(scale); 1442 v.setAlpha(alpha); 1443 1444 // If the view has 0 alpha, we set it to be invisible so as to prevent 1445 // it from accepting touches 1446 if (alpha == 0) { 1447 v.setVisibility(INVISIBLE); 1448 } else if (v.getVisibility() != VISIBLE) { 1449 v.setVisibility(VISIBLE); 1450 } 1451 } 1452 } 1453 1454 enableHwLayersOnVisiblePages(); 1455 } 1456 1457 private void enableHwLayersOnVisiblePages() { 1458 final int screenCount = getChildCount(); 1459 1460 getVisiblePages(mTempVisiblePagesRange); 1461 int leftScreen = mTempVisiblePagesRange[0]; 1462 int rightScreen = mTempVisiblePagesRange[1]; 1463 int forceDrawScreen = -1; 1464 if (leftScreen == rightScreen) { 1465 // make sure we're caching at least two pages always 1466 if (rightScreen < screenCount - 1) { 1467 rightScreen++; 1468 forceDrawScreen = rightScreen; 1469 } else if (leftScreen > 0) { 1470 leftScreen--; 1471 forceDrawScreen = leftScreen; 1472 } 1473 } else { 1474 forceDrawScreen = leftScreen + 1; 1475 } 1476 1477 for (int i = 0; i < screenCount; i++) { 1478 final View layout = (View) getPageAt(i); 1479 if (!(leftScreen <= i && i <= rightScreen && 1480 (i == forceDrawScreen || shouldDrawChild(layout)))) { 1481 layout.setLayerType(LAYER_TYPE_NONE, null); 1482 } 1483 } 1484 1485 for (int i = 0; i < screenCount; i++) { 1486 final View layout = (View) getPageAt(i); 1487 1488 if (leftScreen <= i && i <= rightScreen && 1489 (i == forceDrawScreen || shouldDrawChild(layout))) { 1490 if (layout.getLayerType() != LAYER_TYPE_HARDWARE) { 1491 layout.setLayerType(LAYER_TYPE_HARDWARE, null); 1492 } 1493 } 1494 } 1495 } 1496 1497 protected void overScroll(float amount) { 1498 acceleratedOverScroll(amount); 1499 } 1500 1501 /** 1502 * Used by the parent to get the content width to set the tab bar to 1503 * @return 1504 */ 1505 public int getPageContentWidth() { 1506 return mContentWidth; 1507 } 1508 1509 @Override 1510 protected void onPageEndMoving() { 1511 super.onPageEndMoving(); 1512 mForceDrawAllChildrenNextFrame = true; 1513 // We reset the save index when we change pages so that it will be recalculated on next 1514 // rotation 1515 mSaveInstanceStateItemIndex = -1; 1516 } 1517 1518 /* 1519 * AllAppsView implementation 1520 */ 1521 public void setup(Launcher launcher, DragController dragController) { 1522 mLauncher = launcher; 1523 mDragController = dragController; 1524 } 1525 1526 /** 1527 * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can 1528 * appropriately determine when to invalidate the PagedView page data. In cases where the data 1529 * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the 1530 * next onMeasure() pass, which will trigger an invalidatePageData() itself. 1531 */ 1532 private void invalidateOnDataChange() { 1533 if (!isDataReady()) { 1534 // The next layout pass will trigger data-ready if both widgets and apps are set, so 1535 // request a layout to trigger the page data when ready. 1536 requestLayout(); 1537 } else { 1538 cancelAllTasks(); 1539 invalidatePageData(); 1540 } 1541 } 1542 1543 public void setApps(ArrayList<ApplicationInfo> list) { 1544 mApps = list; 1545 Collections.sort(mApps, LauncherModel.getAppNameComparator()); 1546 updatePageCountsAndInvalidateData(); 1547 } 1548 1549 private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) { 1550 // We add it in place, in alphabetical order 1551 int count = list.size(); 1552 for (int i = 0; i < count; ++i) { 1553 ApplicationInfo info = list.get(i); 1554 int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator()); 1555 if (index < 0) { 1556 mApps.add(-(index + 1), info); 1557 } 1558 } 1559 } 1560 public void addApps(ArrayList<ApplicationInfo> list) { 1561 addAppsWithoutInvalidate(list); 1562 updatePageCountsAndInvalidateData(); 1563 } 1564 private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) { 1565 ComponentName removeComponent = item.intent.getComponent(); 1566 int length = list.size(); 1567 for (int i = 0; i < length; ++i) { 1568 ApplicationInfo info = list.get(i); 1569 if (info.user.equals(item.user) 1570 && info.intent.getComponent().equals(removeComponent)) { 1571 return i; 1572 } 1573 } 1574 return -1; 1575 } 1576 private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) { 1577 // loop through all the apps and remove apps that have the same component 1578 int length = list.size(); 1579 for (int i = 0; i < length; ++i) { 1580 ApplicationInfo info = list.get(i); 1581 int removeIndex = findAppByComponent(mApps, info); 1582 if (removeIndex > -1) { 1583 mApps.remove(removeIndex); 1584 } 1585 } 1586 } 1587 public void removeApps(ArrayList<ApplicationInfo> appInfos) { 1588 removeAppsWithoutInvalidate(appInfos); 1589 updatePageCountsAndInvalidateData(); 1590 } 1591 public void updateApps(ArrayList<ApplicationInfo> list) { 1592 // We remove and re-add the updated applications list because it's properties may have 1593 // changed (ie. the title), and this will ensure that the items will be in their proper 1594 // place in the list. 1595 removeAppsWithoutInvalidate(list); 1596 addAppsWithoutInvalidate(list); 1597 updatePageCountsAndInvalidateData(); 1598 } 1599 1600 public void reset() { 1601 // If we have reset, then we should not continue to restore the previous state 1602 mSaveInstanceStateItemIndex = -1; 1603 1604 AppsCustomizeTabHost tabHost = getTabHost(); 1605 String tag = tabHost.getCurrentTabTag(); 1606 if (tag != null) { 1607 if (!tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) { 1608 tabHost.setCurrentTabFromContent(ContentType.Applications); 1609 } 1610 } 1611 1612 if (mCurrentPage != 0) { 1613 invalidatePageData(0); 1614 } 1615 } 1616 1617 private AppsCustomizeTabHost getTabHost() { 1618 return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane); 1619 } 1620 1621 public void dumpState() { 1622 // TODO: Dump information related to current list of Applications, Widgets, etc. 1623 ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps); 1624 dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets); 1625 } 1626 1627 private void dumpAppWidgetProviderInfoList(String tag, String label, 1628 ArrayList<Object> list) { 1629 Log.d(tag, label + " size=" + list.size()); 1630 for (Object i: list) { 1631 if (i instanceof AppWidgetProviderInfo) { 1632 AppWidgetProviderInfo info = (AppWidgetProviderInfo) i; 1633 Log.d(tag, " label=\"" + info.label + "\" previewImage=" + info.previewImage 1634 + " resizeMode=" + info.resizeMode + " configure=" + info.configure 1635 + " initialLayout=" + info.initialLayout 1636 + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight); 1637 } else if (i instanceof ResolveInfo) { 1638 ResolveInfo info = (ResolveInfo) i; 1639 Log.d(tag, " label=\"" + info.loadLabel(mPackageManager) + "\" icon=" 1640 + info.icon); 1641 } 1642 } 1643 } 1644 1645 public void surrender() { 1646 // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we 1647 // should stop this now. 1648 1649 // Stop all background tasks 1650 cancelAllTasks(); 1651 } 1652 1653 @Override 1654 public void iconPressed(PagedViewIcon icon) { 1655 // Reset the previously pressed icon and store a reference to the pressed icon so that 1656 // we can reset it on return to Launcher (in Launcher.onResume()) 1657 if (mPressedIcon != null) { 1658 mPressedIcon.resetDrawableState(); 1659 } 1660 mPressedIcon = icon; 1661 } 1662 1663 public void resetDrawableState() { 1664 if (mPressedIcon != null) { 1665 mPressedIcon.resetDrawableState(); 1666 mPressedIcon = null; 1667 } 1668 } 1669 1670 /* 1671 * We load an extra page on each side to prevent flashes from scrolling and loading of the 1672 * widget previews in the background with the AsyncTasks. 1673 */ 1674 final static int sLookBehindPageCount = 2; 1675 final static int sLookAheadPageCount = 2; 1676 protected int getAssociatedLowerPageBound(int page) { 1677 final int count = getChildCount(); 1678 int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1); 1679 int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0); 1680 return windowMinIndex; 1681 } 1682 protected int getAssociatedUpperPageBound(int page) { 1683 final int count = getChildCount(); 1684 int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1); 1685 int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1), 1686 count - 1); 1687 return windowMaxIndex; 1688 } 1689 1690 @Override 1691 protected String getCurrentPageDescription() { 1692 int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; 1693 int stringId = R.string.default_scroll_format; 1694 int count = 0; 1695 1696 if (page < mNumAppsPages) { 1697 stringId = R.string.apps_customize_apps_scroll_format; 1698 count = mNumAppsPages; 1699 } else { 1700 page -= mNumAppsPages; 1701 stringId = R.string.apps_customize_widgets_scroll_format; 1702 count = mNumWidgetPages; 1703 } 1704 1705 return String.format(getContext().getString(stringId), page + 1, count); 1706 } 1707} 1708