1785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung/*
2785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Copyright (C) 2011 The Android Open Source Project
3785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung *
4785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Licensed under the Apache License, Version 2.0 (the "License");
5785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * you may not use this file except in compliance with the License.
6785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * You may obtain a copy of the License at
7785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung *
8785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung *      http://www.apache.org/licenses/LICENSE-2.0
9785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung *
10785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Unless required by applicable law or agreed to in writing, software
11785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * distributed under the License is distributed on an "AS IS" BASIS,
12785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * See the License for the specific language governing permissions and
14785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * limitations under the License.
15785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung */
16785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
17785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungpackage com.android.launcher2;
18785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
1955b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chungimport android.animation.AnimatorSet;
20d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chungimport android.animation.ValueAnimator;
21ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohenimport android.appwidget.AppWidgetHostView;
22785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.appwidget.AppWidgetManager;
23785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.appwidget.AppWidgetProviderInfo;
24785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.ComponentName;
25785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.Context;
26785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.Intent;
27374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasaniimport android.content.pm.LauncherActivityInfo;
28374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasaniimport android.content.pm.LauncherApps;
29785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.pm.PackageManager;
30785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.pm.ResolveInfo;
31f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chungimport android.content.res.Configuration;
32785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.res.Resources;
33785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.res.TypedArray;
34785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.graphics.Bitmap;
35785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.graphics.Canvas;
3605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Point;
37785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.graphics.Rect;
38785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.graphics.drawable.Drawable;
39b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chungimport android.os.AsyncTask;
409e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohenimport android.os.Build;
419e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohenimport android.os.Bundle;
42b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chungimport android.os.Process;
43785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.util.AttributeSet;
44785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.util.Log;
45374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasaniimport android.util.SparseArray;
4672d8b393b03f9decba05b0797608ccdc751fecefWinson Chungimport android.view.Gravity;
47c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chungimport android.view.KeyEvent;
48785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.view.LayoutInflater;
49785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.view.View;
5063257c110a4ee54d5e8872c471cce254cf613c7aWinson Chungimport android.view.ViewGroup;
5155b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chungimport android.view.animation.AccelerateInterpolator;
522591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohenimport android.view.animation.DecelerateInterpolator;
53fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chungimport android.widget.GridLayout;
54785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.widget.ImageView;
5555b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chungimport android.widget.Toast;
56785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
57785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport com.android.launcher.R;
58c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport com.android.launcher2.DropTarget.DragObject;
59c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
60c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
61c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Collections;
62c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Iterator;
63c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.List;
64785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
65b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung/**
66b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung * A simple callback interface which also provides the results of the task.
67b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung */
68b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chunginterface AsyncTaskCallback {
69b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data);
70b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung}
714e076545e4ccdbd3c045a3fa33869a2b7519a0ccWinson Chung
72b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung/**
73b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung * The data needed to perform either of the custom AsyncTasks.
74b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung */
75b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chungclass AsyncTaskPageData {
76875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung    enum Type {
7782369a16126a1030c1c9203dc62b33c2598add89Michael Jurka        LoadWidgetPreviewData
78875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung    }
79875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung
80038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka    AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR,
813f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka            AsyncTaskCallback postR, WidgetPreviewLoader w) {
82b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        page = p;
83b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        items = l;
844e076545e4ccdbd3c045a3fa33869a2b7519a0ccWinson Chung        generatedImages = new ArrayList<Bitmap>();
85038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        maxImageWidth = cw;
86038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        maxImageHeight = ch;
87b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        doInBackgroundCallback = bgR;
88b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        postExecuteCallback = postR;
893f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka        widgetPreviewLoader = w;
90b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
91099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung    void cleanup(boolean cancelled) {
92099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung        // Clean up any references to source/generated bitmaps
93099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung        if (generatedImages != null) {
94099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung            if (cancelled) {
9505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka                for (int i = 0; i < generatedImages.size(); i++) {
96ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka                    widgetPreviewLoader.recycleBitmap(items.get(i), generatedImages.get(i));
97099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                }
98099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung            }
99099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung            generatedImages.clear();
100099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung        }
101099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung    }
102b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    int page;
103b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    ArrayList<Object> items;
1044e076545e4ccdbd3c045a3fa33869a2b7519a0ccWinson Chung    ArrayList<Bitmap> sourceImages;
1054e076545e4ccdbd3c045a3fa33869a2b7519a0ccWinson Chung    ArrayList<Bitmap> generatedImages;
106038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka    int maxImageWidth;
107038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka    int maxImageHeight;
108b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    AsyncTaskCallback doInBackgroundCallback;
109b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    AsyncTaskCallback postExecuteCallback;
1103f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka    WidgetPreviewLoader widgetPreviewLoader;
111b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung}
1124e076545e4ccdbd3c045a3fa33869a2b7519a0ccWinson Chung
113b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung/**
114b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung * A generic template for an async task used in AppsCustomize.
115b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung */
116b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chungclass AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTaskPageData> {
1170cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    AppsCustomizeAsyncTask(int p, AsyncTaskPageData.Type ty) {
118b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        page = p;
119b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        threadPriority = Process.THREAD_PRIORITY_DEFAULT;
120875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung        dataType = ty;
121b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
122b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    @Override
123b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    protected AsyncTaskPageData doInBackground(AsyncTaskPageData... params) {
124b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        if (params.length != 1) return null;
125b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        // Load each of the widget previews in the background
126b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        params[0].doInBackgroundCallback.run(this, params[0]);
127b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        return params[0];
128b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
129b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    @Override
130b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    protected void onPostExecute(AsyncTaskPageData result) {
131b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        // All the widget previews are loaded, so we can just callback to inflate the page
132b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        result.postExecuteCallback.run(this, result);
133b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
134b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
135b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    void setThreadPriority(int p) {
136b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        threadPriority = p;
137b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
138b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    void syncThreadPriority() {
139b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        Process.setThreadPriority(threadPriority);
140b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
141b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
142b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    // The page that this async task is associated with
143875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung    AsyncTaskPageData.Type dataType;
144b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    int page;
145b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    int threadPriority;
146b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung}
147b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
148b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung/**
149b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
150b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung */
151785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungpublic class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
152cd81073eac537e9f85eeee14588d513ea8a56e17Winson Chung        View.OnClickListener, View.OnKeyListener, DragSource,
15339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
15439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        LauncherTransitionable {
1550e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen    static final String TAG = "AppsCustomizePagedView";
156785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
157785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    /**
158785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * The different content types that this paged view can show.
159785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     */
160785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public enum ContentType {
161785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        Applications,
1626a26e5bed48bf64996aef3ea1db4767ee147640eWinson Chung        Widgets
163785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
164785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
165785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    // Refs
166785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private Launcher mLauncher;
167785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private DragController mDragController;
168785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private final LayoutInflater mLayoutInflater;
169785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private final PackageManager mPackageManager;
170785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
1715afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    // Save and Restore
1725afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    private int mSaveInstanceStateItemIndex = -1;
173e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung    private PagedViewIcon mPressedIcon;
1745afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung
175785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    // Content
176785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private ArrayList<ApplicationInfo> mApps;
177d294526ad99db70d882a1e11f2b0f878524163faWinson Chung    private ArrayList<Object> mWidgets;
1781ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung
1797d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung    // Cling
1803f4e1423804d64a38cb69e4511d7b80783564827Winson Chung    private boolean mHasShownAllAppsCling;
1817d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung    private int mClingFocusedX;
1827d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung    private int mClingFocusedY;
1837d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung
1841ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung    // Caching
185b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    private Canvas mCanvas;
1864dbea7920a5f52df1d35009352f7e5cba16c05fbWinson Chung    private IconCache mIconCache;
187785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
188785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    // Dimens
189785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private int mContentWidth;
1906032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung    private int mMaxAppCellCountX, mMaxAppCellCountY;
1914b576be59e58072cc03b5a8d36afb6a322513575Winson Chung    private int mWidgetCountX, mWidgetCountY;
192d294526ad99db70d882a1e11f2b0f878524163faWinson Chung    private int mWidgetWidthGap, mWidgetHeightGap;
193785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private PagedViewCellLayout mWidgetSpacingLayout;
1940cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    private int mNumAppsPages;
1950cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    private int mNumWidgetPages;
196785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
19722f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    // Relating to the scroll and overscroll effects
19822f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f);
199cff6af81d721415785bddc2efd74e179d2def9daAdam Cohen    private static float CAMERA_DISTANCE = 6500;
200b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private static float TRANSITION_SCALE_FACTOR = 0.74f;
201cff6af81d721415785bddc2efd74e179d2def9daAdam Cohen    private static float TRANSITION_PIVOT = 0.65f;
202cff6af81d721415785bddc2efd74e179d2def9daAdam Cohen    private static float TRANSITION_MAX_ROTATION = 22;
203cff6af81d721415785bddc2efd74e179d2def9daAdam Cohen    private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
204b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f);
2052591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohen    private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4);
20622f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
207b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    // Previews & outlines
208b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
20968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung    private static final int sPageSleepDelay = 200;
2104b576be59e58072cc03b5a8d36afb6a322513575Winson Chung
211ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    private Runnable mInflateWidgetRunnable = null;
212ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    private Runnable mBindWidgetRunnable = null;
213ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
21421a170b2e17621583f2800d5611459a0a939f560Adam Cohen    static final int WIDGET_PRELOAD_PENDING = 0;
21521a170b2e17621583f2800d5611459a0a939f560Adam Cohen    static final int WIDGET_BOUND = 1;
21621a170b2e17621583f2800d5611459a0a939f560Adam Cohen    static final int WIDGET_INFLATED = 2;
217ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
218ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    int mWidgetLoadingId = -1;
2191b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen    PendingAddWidgetInfo mCreateWidgetInfo = null;
2207a326648c54922c60c32088e173c93068a82d107Adam Cohen    private boolean mDraggingWidget = false;
221ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
222cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung    private Toast mWidgetInstructionToast;
223cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung
22439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    // Deferral of loading widget previews during launcher transitions
22539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    private boolean mInTransition;
22639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    private ArrayList<AsyncTaskPageData> mDeferredSyncWidgetPageItems =
22739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        new ArrayList<AsyncTaskPageData>();
228f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka    private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
229f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka        new ArrayList<Runnable>();
23039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka
2319e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen    private Rect mTmpRect = new Rect();
2329e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen
233dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    // Used for drawing shortcut previews
234dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache();
235dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    PaintCache mCachedShortcutPreviewPaint = new PaintCache();
236dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache();
237dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka
238dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    // Used for drawing widget previews
239dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache();
240dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    RectCache mCachedAppWidgetPreviewSrcRect = new RectCache();
241dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    RectCache mCachedAppWidgetPreviewDestRect = new RectCache();
242dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka    PaintCache mCachedAppWidgetPreviewPaint = new PaintCache();
243dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka
24405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka    WidgetPreviewLoader mWidgetPreviewLoader;
24505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
246c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    private boolean mInBulkBind;
247c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    private boolean mNeedToUpdatePageCountsAndInvalidateData;
248c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka
249785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public AppsCustomizePagedView(Context context, AttributeSet attrs) {
250785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        super(context, attrs);
251785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        mLayoutInflater = LayoutInflater.from(context);
252785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        mPackageManager = context.getPackageManager();
253785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        mApps = new ArrayList<ApplicationInfo>();
2541ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        mWidgets = new ArrayList<Object>();
2554dbea7920a5f52df1d35009352f7e5cba16c05fbWinson Chung        mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache();
256b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        mCanvas = new Canvas();
257b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
2581ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung
2591ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        // Save the default widget preview background
2606032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
2616032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        mMaxAppCellCountX = a.getInt(R.styleable.AppsCustomizePagedView_maxAppCellCountX, -1);
2626032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        mMaxAppCellCountY = a.getInt(R.styleable.AppsCustomizePagedView_maxAppCellCountY, -1);
263f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mWidgetWidthGap =
264f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellWidthGap, 0);
265f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mWidgetHeightGap =
266f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellHeightGap, 0);
2674b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
2684b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
2697d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung        mClingFocusedX = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedX, 0);
2707d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung        mClingFocusedY = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedY, 0);
2714b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        a.recycle();
272f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mWidgetSpacingLayout = new PagedViewCellLayout(getContext());
2734b576be59e58072cc03b5a8d36afb6a322513575Winson Chung
2741ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        // The padding on the non-matched dimension for the default widget preview icons
2751ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        // (top + bottom)
2762591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohen        mFadeInAdjacentScreens = false;
27708055f66528330ff1a1d1d13c856647d86dd967dSvetoslav Ganov
27808055f66528330ff1a1d1d13c856647d86dd967dSvetoslav Ganov        // Unless otherwise specified this view is important for accessibility.
27908055f66528330ff1a1d1d13c856647d86dd967dSvetoslav Ganov        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
28008055f66528330ff1a1d1d13c856647d86dd967dSvetoslav Ganov            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
28108055f66528330ff1a1d1d13c856647d86dd967dSvetoslav Ganov        }
282785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
283785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
284785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    @Override
285785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    protected void init() {
286785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        super.init();
2876a877403542c71c1b6228c429bc060755f5f847bWinson Chung        mCenterPagesVertically = false;
288785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
289785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        Context context = getContext();
290785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        Resources r = context.getResources();
291785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f);
292785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
293785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
2945afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    /** Returns the item index of the center item on this page so that we can restore to this
2955afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung     *  item index when we rotate. */
2965afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    private int getMiddleComponentIndexOnCurrentPage() {
2975afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        int i = -1;
2985afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        if (getPageCount() > 0) {
2995afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung            int currentPage = getCurrentPage();
3000cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            if (currentPage < mNumAppsPages) {
30122f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(currentPage);
3025afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                PagedViewCellLayoutChildren childrenLayout = layout.getChildrenLayout();
3035afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                int numItemsPerPage = mCellCountX * mCellCountY;
3045afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                int childCount = childrenLayout.getChildCount();
3055afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                if (childCount > 0) {
3065afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                    i = (currentPage * numItemsPerPage) + (childCount / 2);
3070cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                }
3080cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            } else {
3090cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                int numApps = mApps.size();
31022f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
3115afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                int numItemsPerPage = mWidgetCountX * mWidgetCountY;
3125afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                int childCount = layout.getChildCount();
3135afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung                if (childCount > 0) {
3140cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                    i = numApps +
3150cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                        ((currentPage - mNumAppsPages) * numItemsPerPage) + (childCount / 2);
3160cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                }
3175afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung            }
3185afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        }
3195afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        return i;
3205afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    }
3215afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung
3225afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    /** Get the index of the item to restore to if we need to restore the current page. */
3235afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    int getSaveInstanceStateIndex() {
3245afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        if (mSaveInstanceStateItemIndex == -1) {
3255afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung            mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage();
3265afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        }
3275afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        return mSaveInstanceStateItemIndex;
3285afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    }
3295afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung
3305afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    /** Returns the page in the current orientation which is expected to contain the specified
3315afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung     *  item index. */
3325afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    int getPageForComponent(int index) {
3330cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        if (index < 0) return 0;
3340cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
3350cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        if (index < mApps.size()) {
3365afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung            int numItemsPerPage = mCellCountX * mCellCountY;
3375afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung            return (index / numItemsPerPage);
3380cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        } else {
3395afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung            int numItemsPerPage = mWidgetCountX * mWidgetCountY;
3400cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            return mNumAppsPages + ((index - mApps.size()) / numItemsPerPage);
3410cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        }
3425afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    }
3435afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung
3445afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    /** Restores the page for an item at the specified index */
3455afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    void restorePageForIndex(int index) {
3465afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        if (index < 0) return;
3470cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        mSaveInstanceStateItemIndex = index;
3485afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung    }
3495afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung
3504b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung    private void updatePageCounts() {
3514b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung        mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
3524b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung                (float) (mWidgetCountX * mWidgetCountY));
3534b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung        mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
3544b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung    }
3554b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung
356f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    protected void onDataReady(int width, int height) {
3573f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka        if (mWidgetPreviewLoader == null) {
3583f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka            mWidgetPreviewLoader = new WidgetPreviewLoader(mLauncher);
3593f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka        }
3603f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka
361f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        // Note that we transpose the counts in portrait so that we get a similar layout
362f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        boolean isLandscape = getResources().getConfiguration().orientation ==
363f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            Configuration.ORIENTATION_LANDSCAPE;
364f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        int maxCellCountX = Integer.MAX_VALUE;
365f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        int maxCellCountY = Integer.MAX_VALUE;
366f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        if (LauncherApplication.isScreenLarge()) {
367f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            maxCellCountX = (isLandscape ? LauncherModel.getCellCountX() :
368f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                LauncherModel.getCellCountY());
369f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            maxCellCountY = (isLandscape ? LauncherModel.getCellCountY() :
370f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                LauncherModel.getCellCountX());
371f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        }
3726032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        if (mMaxAppCellCountX > -1) {
3736032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung            maxCellCountX = Math.min(maxCellCountX, mMaxAppCellCountX);
3746032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        }
375244ebcd7b41fea9edbbbd12525973b1c6d6bcfe1Michael Jurka        // Temp hack for now: only use the max cell count Y for widget layout
376244ebcd7b41fea9edbbbd12525973b1c6d6bcfe1Michael Jurka        int maxWidgetCellCountY = maxCellCountY;
3776032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        if (mMaxAppCellCountY > -1) {
378244ebcd7b41fea9edbbbd12525973b1c6d6bcfe1Michael Jurka            maxWidgetCellCountY = Math.min(maxWidgetCellCountY, mMaxAppCellCountY);
3796032e7ed8e6208348a6b3f8bc1a7ecafc7951af8Winson Chung        }
380f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung
381f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        // Now that the data is ready, we can calculate the content width, the number of cells to
382f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        // use for each page
383f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mWidgetSpacingLayout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
384f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mWidgetSpacingLayout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
385f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
386f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mWidgetSpacingLayout.calculateCellCount(width, height, maxCellCountX, maxCellCountY);
387f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mCellCountX = mWidgetSpacingLayout.getCellCountX();
388f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mCellCountY = mWidgetSpacingLayout.getCellCountY();
3894b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung        updatePageCounts();
3905a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung
391db1138b4efae89a3b5833547958a3606e5408a71Winson Chung        // Force a measure to update recalculate the gaps
392db1138b4efae89a3b5833547958a3606e5408a71Winson Chung        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
393db1138b4efae89a3b5833547958a3606e5408a71Winson Chung        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
394244ebcd7b41fea9edbbbd12525973b1c6d6bcfe1Michael Jurka        mWidgetSpacingLayout.calculateCellCount(width, height, maxCellCountX, maxWidgetCellCountY);
395db1138b4efae89a3b5833547958a3606e5408a71Winson Chung        mWidgetSpacingLayout.measure(widthSpec, heightSpec);
396f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        mContentWidth = mWidgetSpacingLayout.getContentWidth();
3970cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
398e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        AppsCustomizeTabHost host = (AppsCustomizeTabHost) getTabHost();
399e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        final boolean hostIsTransitioning = host.isTransitioning();
400e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka
4010cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        // Restore the page
4020cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        int page = getPageForComponent(mSaveInstanceStateItemIndex);
403e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        invalidatePageData(Math.max(0, page), hostIsTransitioning);
4047d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung
4053f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        // Show All Apps cling if we are finished transitioning, otherwise, we will try again when
4063f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        // the transition completes in AppsCustomizeTabHost (otherwise the wrong offsets will be
4073f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        // returned while animating)
408e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        if (!hostIsTransitioning) {
4093f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            post(new Runnable() {
4103f4e1423804d64a38cb69e4511d7b80783564827Winson Chung                @Override
4113f4e1423804d64a38cb69e4511d7b80783564827Winson Chung                public void run() {
4123f4e1423804d64a38cb69e4511d7b80783564827Winson Chung                    showAllAppsCling();
4133f4e1423804d64a38cb69e4511d7b80783564827Winson Chung                }
4143f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            });
4153f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        }
4163f4e1423804d64a38cb69e4511d7b80783564827Winson Chung    }
4177d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung
4183f4e1423804d64a38cb69e4511d7b80783564827Winson Chung    void showAllAppsCling() {
4199802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung        if (!mHasShownAllAppsCling && isDataReady()) {
4203f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            mHasShownAllAppsCling = true;
4213f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            // Calculate the position for the cling punch through
4223f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            int[] offset = new int[2];
4233f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            int[] pos = mWidgetSpacingLayout.estimateCellPosition(mClingFocusedX, mClingFocusedY);
4243f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            mLauncher.getDragLayer().getLocationInDragLayer(this, offset);
4253f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            // PagedViews are centered horizontally but top aligned
4267819abd2d191a170cbc9d4bd190001c465187a9dWinson Chung            // Note we have to shift the items up now that Launcher sits under the status bar
4273f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            pos[0] += (getMeasuredWidth() - mWidgetSpacingLayout.getMeasuredWidth()) / 2 +
4283f4e1423804d64a38cb69e4511d7b80783564827Winson Chung                    offset[0];
4297819abd2d191a170cbc9d4bd190001c465187a9dWinson Chung            pos[1] += offset[1] - mLauncher.getDragLayer().getPaddingTop();
4303f4e1423804d64a38cb69e4511d7b80783564827Winson Chung            mLauncher.showFirstRunAllAppsCling(pos);
4313f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        }
432f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    }
433f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung
434f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    @Override
435f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
436f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        int width = MeasureSpec.getSize(widthMeasureSpec);
437f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        int height = MeasureSpec.getSize(heightMeasureSpec);
438f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        if (!isDataReady()) {
439374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani            if (mApps.size() > 0 && !mWidgets.isEmpty()) {
440f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                setDataIsReady();
441f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                setMeasuredDimension(width, height);
442f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                onDataReady(width, height);
443f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            }
444f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        }
445f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung
446f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
447f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    }
448f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung
449c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) {
4501ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        // Get the list of widgets and shortcuts
4511ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        mWidgets.clear();
452c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        for (Object o : widgetsAndShortcuts) {
453c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            if (o instanceof AppWidgetProviderInfo) {
454c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                AppWidgetProviderInfo widget = (AppWidgetProviderInfo) o;
455c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                if (widget.minWidth > 0 && widget.minHeight > 0) {
456c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    // Ensure that all widgets we show can be added on a workspace of this size
457c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
458c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget);
459c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    int minSpanX = Math.min(spanXY[0], minSpanXY[0]);
460c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    int minSpanY = Math.min(spanXY[1], minSpanXY[1]);
461c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    if (minSpanX <= LauncherModel.getCellCountX() &&
462336d491492ae15cc97aebb2f9b263c8ec3718dcbAdam Cohen                        minSpanY <= LauncherModel.getCellCountY()) {
463c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                        mWidgets.add(widget);
464c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    } else {
465c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                        Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" +
466c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                              widget.minWidth + ", " + widget.minHeight + ")");
467c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    }
468fd39d8ee9512d873aaaa205839ca233c2be4d9d3Winson Chung                } else {
469c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                    Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" +
470c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                          widget.minWidth + ", " + widget.minHeight + ")");
471a5c9636f563a2fa5bd3c97266894e002453b13dcWinson Chung                }
472dbc1f657863dd9c57a2d30381d3fb36bc7076456Michael Jurka            } else {
473c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                // just add shortcuts
474c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                mWidgets.add(o);
475c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            }
476c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        }
477c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        updatePageCountsAndInvalidateData();
478c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    }
479c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka
480c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    public void setBulkBind(boolean bulkBind) {
481c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        if (bulkBind) {
482c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            mInBulkBind = true;
483c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        } else {
484c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            mInBulkBind = false;
485c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            if (mNeedToUpdatePageCountsAndInvalidateData) {
486c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka                updatePageCountsAndInvalidateData();
487dbc1f657863dd9c57a2d30381d3fb36bc7076456Michael Jurka            }
488dbc1f657863dd9c57a2d30381d3fb36bc7076456Michael Jurka        }
489c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    }
490c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka
491c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka    private void updatePageCountsAndInvalidateData() {
492c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        if (mInBulkBind) {
493c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            mNeedToUpdatePageCountsAndInvalidateData = true;
494c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        } else {
495c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            updatePageCounts();
496c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            invalidateOnDataChange();
497c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka            mNeedToUpdatePageCountsAndInvalidateData = false;
498c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        }
4994b576be59e58072cc03b5a8d36afb6a322513575Winson Chung    }
5004b576be59e58072cc03b5a8d36afb6a322513575Winson Chung
5014b576be59e58072cc03b5a8d36afb6a322513575Winson Chung    @Override
5024b576be59e58072cc03b5a8d36afb6a322513575Winson Chung    public void onClick(View v) {
503fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        // When we have exited all apps or are in transition, disregard clicks
504c93e5ae12018bb214099ff88a48cc21580aec4c3Winson Chung        if (!mLauncher.isAllAppsVisible() ||
505fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen                mLauncher.getWorkspace().isSwitchingState()) return;
506fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
5074b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        if (v instanceof PagedViewIcon) {
5084b576be59e58072cc03b5a8d36afb6a322513575Winson Chung            // Animate some feedback to the click
5094b576be59e58072cc03b5a8d36afb6a322513575Winson Chung            final ApplicationInfo appInfo = (ApplicationInfo) v.getTag();
5103b187b88baf80e520f6bd32d60abe6460d28a040Winson Chung
5113b187b88baf80e520f6bd32d60abe6460d28a040Winson Chung            // Lock the drawable state to pressed until we return to Launcher
5123b187b88baf80e520f6bd32d60abe6460d28a040Winson Chung            if (mPressedIcon != null) {
5133b187b88baf80e520f6bd32d60abe6460d28a040Winson Chung                mPressedIcon.lockDrawableState();
5143b187b88baf80e520f6bd32d60abe6460d28a040Winson Chung            }
515c7450e3ebd7672fcd7b9d51a8c1e68f63c5ce86bWinson Chung
51618f41f8327860d7e257d063888d08b6b5c528fe9Winson Chung            // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
51718f41f8327860d7e257d063888d08b6b5c528fe9Winson Chung            // to be consistent.  So re-enable the flag here, and we will re-disable it as necessary
51818f41f8327860d7e257d063888d08b6b5c528fe9Winson Chung            // when Launcher resumes and we are still in AllApps.
51918f41f8327860d7e257d063888d08b6b5c528fe9Winson Chung            mLauncher.updateWallpaperVisibility(true);
520c7450e3ebd7672fcd7b9d51a8c1e68f63c5ce86bWinson Chung            mLauncher.startActivitySafely(v, appInfo.intent, appInfo);
521c7450e3ebd7672fcd7b9d51a8c1e68f63c5ce86bWinson Chung
5224b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        } else if (v instanceof PagedViewWidget) {
523d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            // Let the user know that they have to long press to add a widget
524cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung            if (mWidgetInstructionToast != null) {
525cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung                mWidgetInstructionToast.cancel();
526cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung            }
527cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung            mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
528cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung                Toast.LENGTH_SHORT);
529cb9ab4f3aa04ad60355d119dfedca3052378d8f9Winson Chung            mWidgetInstructionToast.show();
530d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung
531d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            // Create a little animation to show that the widget can move
532d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
533d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
5342ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
5352ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
536d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            tyuAnim.setDuration(125);
5372ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
538d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            tydAnim.setDuration(100);
539d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            bounce.play(tyuAnim).before(tydAnim);
540d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            bounce.setInterpolator(new AccelerateInterpolator());
541d2e87b32dc8c09590dd1ae186e97d3260955a568Winson Chung            bounce.start();
5424b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        }
543785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
544785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
545c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung    public boolean onKey(View v, int keyCode, KeyEvent event) {
546c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung        return FocusHelper.handleAppsCustomizeKeyEvent(v,  keyCode, event);
547c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung    }
548c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung
549785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    /*
550785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * PagedViewWithDraggableItems implementation
551785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     */
552785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    @Override
553785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    protected void determineDraggingStart(android.view.MotionEvent ev) {
554785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // Disable dragging by pulling an app down for now.
555785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
556785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
557ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    private void beginDraggingApplication(View v) {
558ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        mLauncher.getWorkspace().onDragStartedWithItem(v);
559ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        mLauncher.getWorkspace().beginDragShared(v, this);
5604b576be59e58072cc03b5a8d36afb6a322513575Winson Chung    }
561ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
5629e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen    Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
5639e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen        Bundle options = null;
5649e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
5659e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen            AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, mTmpRect);
566aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(mLauncher,
567aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen                    info.componentName, null);
568aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen
569aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            float density = getResources().getDisplayMetrics().density;
570aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            int xPaddingDips = (int) ((padding.left + padding.right) / density);
571aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
572aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen
5739e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen            options = new Bundle();
574aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
575aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen                    mTmpRect.left - xPaddingDips);
576aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
577aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen                    mTmpRect.top - yPaddingDips);
578aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
579aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen                    mTmpRect.right - xPaddingDips);
580aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
581aaa5c21ee2e03def644fb6ba8eadbb59873ddd45Adam Cohen                    mTmpRect.bottom - yPaddingDips);
5829e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen        }
5839e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen        return options;
5849e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen    }
5859e05a5ea951b4d5ffce324da8dd0656353306e6fAdam Cohen
586f1dcdf61132a6321d0c1c0eb670c6cf1493ab981Adam Cohen    private void preloadWidget(final PendingAddWidgetInfo info) {
587ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        final AppWidgetProviderInfo pInfo = info.info;
588dd70d66852bb8bd16f55796e546ba290360d1198Adam Cohen        final Bundle options = getDefaultOptionsForWidget(mLauncher, info);
589dd70d66852bb8bd16f55796e546ba290360d1198Adam Cohen
590ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        if (pInfo.configure != null) {
591dd70d66852bb8bd16f55796e546ba290360d1198Adam Cohen            info.bindOptions = options;
592ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            return;
593ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        }
594ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
59521a170b2e17621583f2800d5611459a0a939f560Adam Cohen        mWidgetCleanupState = WIDGET_PRELOAD_PENDING;
596ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mBindWidgetRunnable = new Runnable() {
597ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            @Override
598ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            public void run() {
599ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
600610ded21c79ae3da4c105c2d1921a30732468a69Svet Ganov                if (AppWidgetManager.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
601610ded21c79ae3da4c105c2d1921a30732468a69Svet Ganov                        mWidgetLoadingId, info.info.getProfile(), info.componentName, options)) {
602610ded21c79ae3da4c105c2d1921a30732468a69Svet Ganov                    mWidgetCleanupState = WIDGET_BOUND;
6038b805b17158886035b38261eb611d8641701ae43Michael Jurka                }
604ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            }
605ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        };
606ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        post(mBindWidgetRunnable);
607ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
608ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mInflateWidgetRunnable = new Runnable() {
609ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            @Override
610ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            public void run() {
6111637d6d64ac85d75b69b90fd976ed449046ccdc6Michael Jurka                if (mWidgetCleanupState != WIDGET_BOUND) {
6121637d6d64ac85d75b69b90fd976ed449046ccdc6Michael Jurka                    return;
6131637d6d64ac85d75b69b90fd976ed449046ccdc6Michael Jurka                }
6148b805b17158886035b38261eb611d8641701ae43Michael Jurka                AppWidgetHostView hostView = mLauncher.
6158b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getAppWidgetHost().createView(getContext(), mWidgetLoadingId, pInfo);
616ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                info.boundWidget = hostView;
617ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                mWidgetCleanupState = WIDGET_INFLATED;
618ef3dd6efe03c988be1fe980fbed75333017e6760Adam Cohen                hostView.setVisibility(INVISIBLE);
6191f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info.spanX,
6201f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                        info.spanY, info, false);
6211f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen
6221f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                // We want the first widget layout to be the correct size. This will be important
6231f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                // for width size reporting to the AppWidgetManager.
6241f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
6251f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                        unScaledSize[1]);
6261f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                lp.x = lp.y = 0;
6271f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                lp.customPosition = true;
6281f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                hostView.setLayoutParams(lp);
629ef3dd6efe03c988be1fe980fbed75333017e6760Adam Cohen                mLauncher.getDragLayer().addView(hostView);
630ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            }
631ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        };
632ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        post(mInflateWidgetRunnable);
633ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
634ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
635ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    @Override
636ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void onShortPress(View v) {
637ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        // We are anticipating a long press, and we use this time to load bind and instantiate
638ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        // the widget. This will need to be cleaned up if it turns out no long press occurs.
6390e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        if (mCreateWidgetInfo != null) {
6400e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            // Just in case the cleanup process wasn't properly executed. This shouldn't happen.
6410e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            cleanupWidgetPreloading(false);
6420e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        }
6431b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen        mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
644f1dcdf61132a6321d0c1c0eb670c6cf1493ab981Adam Cohen        preloadWidget(mCreateWidgetInfo);
645ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
646ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
6470e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen    private void cleanupWidgetPreloading(boolean widgetWasAdded) {
6480e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        if (!widgetWasAdded) {
6490e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            // If the widget was not added, we may need to do further cleanup.
6500e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            PendingAddWidgetInfo info = mCreateWidgetInfo;
6510e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            mCreateWidgetInfo = null;
65221a170b2e17621583f2800d5611459a0a939f560Adam Cohen
65321a170b2e17621583f2800d5611459a0a939f560Adam Cohen            if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) {
65421a170b2e17621583f2800d5611459a0a939f560Adam Cohen                // We never did any preloading, so just remove pending callbacks to do so
65521a170b2e17621583f2800d5611459a0a939f560Adam Cohen                removeCallbacks(mBindWidgetRunnable);
65621a170b2e17621583f2800d5611459a0a939f560Adam Cohen                removeCallbacks(mInflateWidgetRunnable);
65721a170b2e17621583f2800d5611459a0a939f560Adam Cohen            } else if (mWidgetCleanupState == WIDGET_BOUND) {
65821a170b2e17621583f2800d5611459a0a939f560Adam Cohen                 // Delete the widget id which was allocated
65921a170b2e17621583f2800d5611459a0a939f560Adam Cohen                if (mWidgetLoadingId != -1) {
66021a170b2e17621583f2800d5611459a0a939f560Adam Cohen                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
66121a170b2e17621583f2800d5611459a0a939f560Adam Cohen                }
66221a170b2e17621583f2800d5611459a0a939f560Adam Cohen
66321a170b2e17621583f2800d5611459a0a939f560Adam Cohen                // We never got around to inflating the widget, so remove the callback to do so.
6640e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen                removeCallbacks(mInflateWidgetRunnable);
6650e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            } else if (mWidgetCleanupState == WIDGET_INFLATED) {
66621a170b2e17621583f2800d5611459a0a939f560Adam Cohen                // Delete the widget id which was allocated
66721a170b2e17621583f2800d5611459a0a939f560Adam Cohen                if (mWidgetLoadingId != -1) {
66821a170b2e17621583f2800d5611459a0a939f560Adam Cohen                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
66921a170b2e17621583f2800d5611459a0a939f560Adam Cohen                }
67021a170b2e17621583f2800d5611459a0a939f560Adam Cohen
6710e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen                // The widget was inflated and added to the DragLayer -- remove it.
6720e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen                AppWidgetHostView widget = info.boundWidget;
6730e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen                mLauncher.getDragLayer().removeView(widget);
6740e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            }
675ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        }
676ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
677ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mWidgetLoadingId = -1;
6780e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        mCreateWidgetInfo = null;
6790e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        PagedViewWidget.resetShortPressTarget();
680ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
681ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
6827a326648c54922c60c32088e173c93068a82d107Adam Cohen    @Override
6837a326648c54922c60c32088e173c93068a82d107Adam Cohen    public void cleanUpShortPress(View v) {
6847a326648c54922c60c32088e173c93068a82d107Adam Cohen        if (!mDraggingWidget) {
6850e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen            cleanupWidgetPreloading(false);
6867a326648c54922c60c32088e173c93068a82d107Adam Cohen        }
6877a326648c54922c60c32088e173c93068a82d107Adam Cohen    }
688ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
68988c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen    private boolean beginDraggingWidget(View v) {
6907a326648c54922c60c32088e173c93068a82d107Adam Cohen        mDraggingWidget = true;
6914b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        // Get the widget preview as the drag representation
6924b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
6931ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
6944b576be59e58072cc03b5a8d36afb6a322513575Winson Chung
69588c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
69688c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen        // we abort the drag.
69788c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen        if (image.getDrawable() == null) {
69888c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen            mDraggingWidget = false;
69988c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen            return false;
70088c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen        }
70188c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen
7024b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        // Compose the drag image
7031120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        Bitmap preview;
7041120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        Bitmap outline;
70572d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung        float scale = 1f;
70605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka        Point previewPadding = null;
70705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
7081ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        if (createItemInfo instanceof PendingAddWidgetInfo) {
7099247892015dad231c5005aa021c3e3416265ed80Adam Cohen            // This can happen in some weird cases involving multi-touch. We can't start dragging
7109247892015dad231c5005aa021c3e3416265ed80Adam Cohen            // the widget if this is null, so we break out.
7119247892015dad231c5005aa021c3e3416265ed80Adam Cohen            if (mCreateWidgetInfo == null) {
7129247892015dad231c5005aa021c3e3416265ed80Adam Cohen                return false;
7139247892015dad231c5005aa021c3e3416265ed80Adam Cohen            }
7149247892015dad231c5005aa021c3e3416265ed80Adam Cohen
7151b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen            PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo;
7161b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen            createItemInfo = createWidgetInfo;
7171f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen            int spanX = createItemInfo.spanX;
7181f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen            int spanY = createItemInfo.spanY;
7191f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen            int[] size = mLauncher.getWorkspace().estimateItemSize(spanX, spanY,
7201f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                    createWidgetInfo, true);
7211ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung
72272d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung            FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
72372d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung            float minScale = 1.25f;
724dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka            int maxWidth, maxHeight;
725dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka            maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
726dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka            maxHeight = Math.min((int) (previewDrawable.getIntrinsicHeight() * minScale), size[1]);
72705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
72805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            int[] previewSizeBeforeScale = new int[1];
72905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
730610ded21c79ae3da4c105c2d1921a30732468a69Svet Ganov            preview = mWidgetPreviewLoader.generateWidgetPreview(createWidgetInfo.info, spanX,
731610ded21c79ae3da4c105c2d1921a30732468a69Svet Ganov                    spanY, maxWidth, maxHeight, null, previewSizeBeforeScale);
73205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
73305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            // Compare the size of the drag preview to the preview in the AppsCustomize tray
73405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
73505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka                    mWidgetPreviewLoader.maxWidthForWidgetPreview(spanX));
73605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            scale = previewWidthInAppsCustomize / (float) preview.getWidth();
73705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
73805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            // The bitmap in the AppsCustomize tray is always the the same size, so there
73905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            // might be extra pixels around the preview itself - this accounts for that
74005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
74105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka                int padding =
74205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka                        (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
74305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka                previewPadding = new Point(padding, 0);
74405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            }
7451ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        } else {
746dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka            PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
747374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani            // Widgets are only supported for current user, not for other profiles.
748374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani            // Hence use myUserHandle().
749374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani            Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo,
750374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani                    android.os.Process.myUserHandle());
751dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka            preview = Bitmap.createBitmap(icon.getIntrinsicWidth(),
752dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka                    icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
753dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka
7541120e0355798391712f1d2e2b205f0bd3724770cWinson Chung            mCanvas.setBitmap(preview);
7554ca3922d9d4509b81005ab9625d6d00913911149Michael Jurka            mCanvas.save();
75605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            WidgetPreviewLoader.renderDrawableToBitmap(icon, preview, 0, 0,
757dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka                    icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
7584ca3922d9d4509b81005ab9625d6d00913911149Michael Jurka            mCanvas.restore();
759aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen            mCanvas.setBitmap(null);
7601ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung            createItemInfo.spanX = createItemInfo.spanY = 1;
7611ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        }
7624b576be59e58072cc03b5a8d36afb6a322513575Winson Chung
7638c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        // Don't clip alpha values for the drag outline if we're using the default widget preview
7648c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
765610ded21c79ae3da4c105c2d1921a30732468a69Svet Ganov                (((PendingAddWidgetInfo) createItemInfo).info.previewImage == 0));
7668db7000140d3c35be92a4e07cf54ea6ec4ae3030Peter Ng
7671120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        // Save the preview for the outline generation, then dim the preview
7681120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
7691120e0355798391712f1d2e2b205f0bd3724770cWinson Chung                false);
7701120e0355798391712f1d2e2b205f0bd3724770cWinson Chung
7714b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        // Start the drag
772641d71d6da6c77cc32e5d0f65ccae89caed1ac34Winson Chung        mLauncher.lockScreenOrientation();
7738c3339bde96d11fd1d7f818cd39e7438e309ffd1Michael Jurka        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
7741120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        mDragController.startDrag(image, preview, this, createItemInfo,
77505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka                DragController.DRAG_ACTION_COPY, previewPadding, scale);
7761120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        outline.recycle();
7771120e0355798391712f1d2e2b205f0bd3724770cWinson Chung        preview.recycle();
77888c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen        return true;
7794b576be59e58072cc03b5a8d36afb6a322513575Winson Chung    }
7807d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung
781ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    @Override
782ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    protected boolean beginDragging(final View v) {
7834b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        if (!super.beginDragging(v)) return false;
7844b576be59e58072cc03b5a8d36afb6a322513575Winson Chung
7854b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        if (v instanceof PagedViewIcon) {
7864b576be59e58072cc03b5a8d36afb6a322513575Winson Chung            beginDraggingApplication(v);
7874b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        } else if (v instanceof PagedViewWidget) {
78888c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen            if (!beginDraggingWidget(v)) {
78988c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen                return false;
79088c5d2d8eb895904f4626fb5d2f3e693327de650Adam Cohen            }
7914b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        }
792ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
793ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        // We delay entering spring-loaded mode slightly to make sure the UI
794ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        // thready is free of any work.
795ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        postDelayed(new Runnable() {
796ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            @Override
797ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            public void run() {
7981b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                // We don't enter spring-loaded mode if the drag has been cancelled
7991b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                if (mLauncher.getDragController().isDragging()) {
8001b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                    // Dismiss the cling
8011b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                    mLauncher.dismissAllAppsCling(null);
802ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
8031b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                    // Reset the alpha on the dragged icon before we drag
8041b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                    resetDrawableState();
805ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
8061b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                    // Go into spring loaded mode (must happen before we startDrag())
8071b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                    mLauncher.enterSpringLoadedDragMode();
8081b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen                }
809ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            }
81072d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung        }, 150);
811ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
812785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        return true;
813785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
8141b36dc3f2bb643e3b9600755f1a98522e4efc2edAdam Cohen
815a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    /**
816a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung     * Clean up after dragging.
817a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung     *
818a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung     * @param target where the item was dragged to (can be null if the item was flung)
819a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung     */
820a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    private void endDragging(View target, boolean isFlingToDelete, boolean success) {
821a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
822d4d7aa551ffdc80d810ff970fa72a6509960401eAdam Cohen                !(target instanceof DeleteDropTarget))) {
823557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            // Exit spring loaded mode if we have not successfully dropped or have not handled the
824557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            // drop in Workspace
825557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            mLauncher.exitSpringLoadedDragMode();
826557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        }
8274b919f813f4e5e0323a4c1747392551fce4a8758Winson Chung        mLauncher.unlockScreenOrientation(false);
828785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
829785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
830785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    @Override
831a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka    public View getContent() {
832a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka        return null;
833a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka    }
834a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka
835a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka    @Override
836a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
83739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        mInTransition = true;
83839e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        if (toWorkspace) {
83939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            cancelAllTasks();
84039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        }
84139e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    }
84239e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka
84339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    @Override
844a35e35ae0ac2391b8928eb15bf91274aea96b115Michael Jurka    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
84539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    }
84639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka
84739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    @Override
84839e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    public void onLauncherTransitionStep(Launcher l, float t) {
84939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    }
85039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka
85139e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    @Override
85239e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
85339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        mInTransition = false;
85439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        for (AsyncTaskPageData d : mDeferredSyncWidgetPageItems) {
85539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            onSyncWidgetPageItems(d);
85639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        }
85739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        mDeferredSyncWidgetPageItems.clear();
858f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka        for (Runnable r : mDeferredPrepareLoadWidgetPreviewsTasks) {
859f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka            r.run();
860f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka        }
861f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka        mDeferredPrepareLoadWidgetPreviewsTasks.clear();
8625e368ffbad2fb08e3eadab98eeefd4e1d05bdb2bMichael Jurka        mForceDrawAllChildrenNextFrame = !toWorkspace;
86339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    }
86439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka
86539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    @Override
866a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
867a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung            boolean success) {
868a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling
869a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        if (isFlingToDelete) return;
870a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
871a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        endDragging(target, false, success);
872fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung
873fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung        // Display an error message if the drag failed due to there not being enough space on the
874fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung        // target layout we were dropping on.
875fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung        if (!success) {
876fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung            boolean showOutOfSpaceMessage = false;
877fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung            if (target instanceof Workspace) {
878fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
879fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                Workspace workspace = (Workspace) target;
880fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
881c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
882fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                if (layout != null) {
883fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                    layout.calculateSpans(itemInfo);
884fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                    showOutOfSpaceMessage =
885fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
886fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung                }
887fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung            }
888fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung            if (showOutOfSpaceMessage) {
88993eef082ec2da802ee4507fb2ca729e550f833f1Winson Chung                mLauncher.showOutOfSpaceMessage(false);
890fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung            }
8917a326648c54922c60c32088e173c93068a82d107Adam Cohen
8927bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            d.deferDragViewCleanupPostAnimation = false;
893fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung        }
8940e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        cleanupWidgetPreloading(success);
8957a326648c54922c60c32088e173c93068a82d107Adam Cohen        mDraggingWidget = false;
896785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
897785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
898a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    @Override
899a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    public void onFlingToDeleteCompleted() {
900a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        // We just dismiss the drag when we fling, so cleanup here
901a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        endDragging(null, true, true);
9020e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        cleanupWidgetPreloading(false);
903a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        mDraggingWidget = false;
904a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    }
905a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
906a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    @Override
907043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public boolean supportsFlingToDelete() {
908a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        return true;
909043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
910043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
9117f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung    @Override
9127f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung    protected void onDetachedFromWindow() {
9137f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung        super.onDetachedFromWindow();
9140cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        cancelAllTasks();
9150cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    }
9167f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung
917e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka    public void clearAllWidgetPages() {
918e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        cancelAllTasks();
919e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        int count = getChildCount();
920e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        for (int i = 0; i < count; i++) {
921e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka            View v = getPageAt(i);
922e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka            if (v instanceof PagedViewGridLayout) {
923e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka                ((PagedViewGridLayout) v).removeAllViewsOnPage();
924e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka                mDirtyPageContent.set(i, true);
925e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka            }
926e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka        }
927e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka    }
928e326f186af6b00e4ea32849f1527254c669d0600Michael Jurka
9290cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    private void cancelAllTasks() {
9307f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung        // Clean up all the async tasks
9317f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
9327f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung        while (iter.hasNext()) {
9337f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
9347f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung            task.cancel(false);
9357f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung            iter.remove();
93639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            mDirtyPageContent.set(task.page, true);
9377ce9985d37e253a93617404d5991017e1ea81907Winson Chung
9387ce9985d37e253a93617404d5991017e1ea81907Winson Chung            // We've already preallocated the views for the data to load into, so clear them as well
9397ce9985d37e253a93617404d5991017e1ea81907Winson Chung            View v = getPageAt(task.page);
9407ce9985d37e253a93617404d5991017e1ea81907Winson Chung            if (v instanceof PagedViewGridLayout) {
9417ce9985d37e253a93617404d5991017e1ea81907Winson Chung                ((PagedViewGridLayout) v).removeAllViewsOnPage();
9427ce9985d37e253a93617404d5991017e1ea81907Winson Chung            }
9437f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung        }
94483687b1e5bd887cb9eb3566fe27745c1b31d09f8Winson Chung        mDeferredSyncWidgetPageItems.clear();
945f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka        mDeferredPrepareLoadWidgetPreviewsTasks.clear();
9467f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung    }
9477f0acdde9679eb545abb8bc5373e1938c420bf63Winson Chung
948785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void setContentType(ContentType type) {
9490cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        if (type == ContentType.Widgets) {
9500cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            invalidatePageData(mNumAppsPages, true);
9510cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        } else if (type == ContentType.Applications) {
9520cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            invalidatePageData(0, true);
9530cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        }
954b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
955b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
9560cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    protected void snapToPage(int whichPage, int delta, int duration) {
9570cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        super.snapToPage(whichPage, delta, duration);
9580cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        updateCurrentTab(whichPage);
95968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung
96068e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // Update the thread priorities given the direction lookahead
96168e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
96268e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        while (iter.hasNext()) {
96368e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
96439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            int pageIndex = task.page;
96568e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
96668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung                (mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
96768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung                task.setThreadPriority(getThreadPriorityForPage(pageIndex));
96868e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            } else {
96968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung                task.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
97068e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            }
97168e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        }
9720cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    }
9730cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
9740cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    private void updateCurrentTab(int currentPage) {
9750cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        AppsCustomizeTabHost tabHost = getTabHost();
976c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung        if (tabHost != null) {
977c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung            String tag = tabHost.getCurrentTabTag();
978c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung            if (tag != null) {
979c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                if (currentPage >= mNumAppsPages &&
980c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                        !tag.equals(tabHost.getTabTagForContentType(ContentType.Widgets))) {
981c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                    tabHost.setCurrentTabFromContent(ContentType.Widgets);
982c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                } else if (currentPage < mNumAppsPages &&
983c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                        !tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) {
984c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                    tabHost.setCurrentTabFromContent(ContentType.Applications);
985c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung                }
9866a8103c7efcaf6ea6e3170b36bf96dcfc1fa36b3Winson Chung            }
9870cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        }
9880cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    }
9890cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
990785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    /*
991785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * Apps PagedView implementation
992785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     */
99363257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung    private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
99463257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        int childCount = layout.getChildCount();
99563257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        for (int i = 0; i < childCount; ++i) {
99663257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung            layout.getChildAt(i).setVisibility(visibility);
99763257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        }
99863257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung    }
999785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private void setupPage(PagedViewCellLayout layout) {
1000785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.setCellCount(mCellCountX, mCellCountY);
1001785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
1002785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
1003785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
1004785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
100563257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        // Note: We force a measure here to get around the fact that when we do layout calculations
100663257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        // immediately after syncing, we don't have a proper width.  That said, we already know the
100763257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        // expected page width, so we can actually optimize by hiding all the TextView-based
100863257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        // children that are expensive to measure, and let that happen naturally later.
100963257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        setVisibilityOnChildren(layout, View.GONE);
1010db1138b4efae89a3b5833547958a3606e5408a71Winson Chung        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
1011785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
101263257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        layout.setMinimumWidth(getPageContentWidth());
1013785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.measure(widthSpec, heightSpec);
101463257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        setVisibilityOnChildren(layout, View.VISIBLE);
1015785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
10160cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
1017f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung    public void syncAppsPageItems(int page, boolean immediate) {
1018785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // ensure that we have the right number of items on the pages
1019fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        final boolean isRtl = isLayoutRtl();
1020785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int numCells = mCellCountX * mCellCountY;
1021785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int startIndex = page * numCells;
1022785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int endIndex = Math.min(startIndex + numCells, mApps.size());
102322f823d340710bcde587b18a1542570cbe0360f5Adam Cohen        PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(page);
1024875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung
1025785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.removeAllViewsOnPage();
1026b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        ArrayList<Object> items = new ArrayList<Object>();
1027b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        ArrayList<Bitmap> images = new ArrayList<Bitmap>();
1028785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        for (int i = startIndex; i < endIndex; ++i) {
1029785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            ApplicationInfo info = mApps.get(i);
1030785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate(
1031785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                    R.layout.apps_customize_application, layout, false);
1032e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung            icon.applyFromApplicationInfo(info, true, this);
1033785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            icon.setOnClickListener(this);
1034785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            icon.setOnLongClickListener(this);
1035785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            icon.setOnTouchListener(this);
1036c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung            icon.setOnKeyListener(this);
1037785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
1038785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            int index = i - startIndex;
1039785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            int x = index % mCellCountX;
1040785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            int y = index / mCellCountX;
1041fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            if (isRtl) {
1042fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung                x = mCellCountX - x - 1;
1043fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            }
10446a70e9fc3c62cc83d6abe59323d622dc6cd224a7Winson Chung            layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
1045b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
1046b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            items.add(info);
1047b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            images.add(info.iconBitmap);
1048785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1049f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung
105047639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        enableHwLayersOnVisiblePages();
1051b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
1052b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
1053b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    /**
105468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung     * A helper to return the priority for loading of the specified widget page.
105568e4c64a67f4a40afac4cab44def461783f096a4Winson Chung     */
105668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung    private int getWidgetPageLoadPriority(int page) {
105768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // If we are snapping to another page, use that index as the target page index
105868e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int toPage = mCurrentPage;
105968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        if (mNextPage > -1) {
106068e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            toPage = mNextPage;
106168e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        }
106268e4c64a67f4a40afac4cab44def461783f096a4Winson Chung
106368e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // We use the distance from the target page as an initial guess of priority, but if there
106468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // are no pages of higher priority than the page specified, then bump up the priority of
106568e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // the specified page.
106668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
106768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int minPageDiff = Integer.MAX_VALUE;
106868e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        while (iter.hasNext()) {
106968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
107039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            minPageDiff = Math.abs(task.page - toPage);
107168e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        }
107268e4c64a67f4a40afac4cab44def461783f096a4Winson Chung
107368e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int rawPageDiff = Math.abs(page - toPage);
107468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        return rawPageDiff - Math.min(rawPageDiff, minPageDiff);
107568e4c64a67f4a40afac4cab44def461783f096a4Winson Chung    }
107668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung    /**
1077b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     * Return the appropriate thread priority for loading for a given page (we give the current
1078b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     * page much higher priority)
1079b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     */
1080b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    private int getThreadPriorityForPage(int page) {
1081b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        // TODO-APPS_CUSTOMIZE: detect number of cores and set thread priorities accordingly below
108268e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int pageDiff = getWidgetPageLoadPriority(page);
1083b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        if (pageDiff <= 0) {
108468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            return Process.THREAD_PRIORITY_LESS_FAVORABLE;
1085b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        } else if (pageDiff <= 1) {
108668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            return Process.THREAD_PRIORITY_LOWEST;
1087b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        } else {
108868e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            return Process.THREAD_PRIORITY_LOWEST;
1089b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        }
1090785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1091f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung    private int getSleepForPage(int page) {
109268e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int pageDiff = getWidgetPageLoadPriority(page);
1093f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        return Math.max(0, pageDiff * sPageSleepDelay);
1094f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung    }
1095b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    /**
1096b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     * Creates and executes a new AsyncTask to load a page of widget previews.
1097b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     */
1098b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    private void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets,
1099d294526ad99db70d882a1e11f2b0f878524163faWinson Chung            int cellWidth, int cellHeight, int cellCountX) {
110068e4c64a67f4a40afac4cab44def461783f096a4Winson Chung
1101b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        // Prune all tasks that are no longer needed
1102b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
1103b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        while (iter.hasNext()) {
1104b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
110539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            int taskPage = task.page;
110668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung            if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
110768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung                    taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
1108b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                task.cancel(false);
1109b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                iter.remove();
1110b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            } else {
111168e4c64a67f4a40afac4cab44def461783f096a4Winson Chung                task.setThreadPriority(getThreadPriorityForPage(taskPage));
1112b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            }
1113b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        }
1114b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
1115f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        // We introduce a slight delay to order the loading of side pages so that we don't thrash
111639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        final int sleepMs = getSleepForPage(page);
1117b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        AsyncTaskPageData pageData = new AsyncTaskPageData(page, widgets, cellWidth, cellHeight,
1118038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka            new AsyncTaskCallback() {
1119b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                @Override
1120b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
1121f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung                    try {
1122099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                        try {
1123099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                            Thread.sleep(sleepMs);
1124099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                        } catch (Exception e) {}
1125099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                        loadWidgetPreviewsInBackground(task, data);
1126099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                    } finally {
1127099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                        if (task.isCancelled()) {
1128099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                            data.cleanup(true);
1129099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                        }
1130099459377a737d885bbd8ac4d52e6884a103b1c7Winson Chung                    }
1131b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                }
1132b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            },
1133b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung            new AsyncTaskCallback() {
1134b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                @Override
1135b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
113639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                    mRunningTasks.remove(task);
113739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                    if (task.isCancelled()) return;
113839e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                    // do cleanup inside onSyncWidgetPageItems
113939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                    onSyncWidgetPageItems(data);
1140b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung                }
11413f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka            }, mWidgetPreviewLoader);
1142b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
1143b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        // Ensure that the task is appropriately prioritized and runs in parallel
11440cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        AppsCustomizeAsyncTask t = new AppsCustomizeAsyncTask(page,
1145875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung                AsyncTaskPageData.Type.LoadWidgetPreviewData);
114639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        t.setThreadPriority(getThreadPriorityForPage(page));
1147b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        t.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pageData);
1148b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        mRunningTasks.add(t);
1149b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
1150b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
1151785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    /*
1152785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * Widgets PagedView implementation
1153785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     */
11544e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    private void setupPage(PagedViewGridLayout layout) {
1155785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
1156785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
115763257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung
115863257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        // Note: We force a measure here to get around the fact that when we do layout calculations
1159d52f3d84fc1df6b4c1ae1101eb937ae4eeb32e75Winson Chung        // immediately after syncing, we don't have a proper width.
116063257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
116163257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
1162785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        layout.setMinimumWidth(getPageContentWidth());
116363257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung        layout.measure(widthSpec, heightSpec);
1164785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
11650cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
1166038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka    public void syncWidgetPageItems(final int page, final boolean immediate) {
11676a3fd3f042c8bfa7d83e29c1eeadff21323ab089Winson Chung        int numItemsPerPage = mWidgetCountX * mWidgetCountY;
1168d294526ad99db70d882a1e11f2b0f878524163faWinson Chung
11694b576be59e58072cc03b5a8d36afb6a322513575Winson Chung        // Calculate the dimensions of each cell we are giving to each widget
1170038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        final ArrayList<Object> items = new ArrayList<Object>();
1171038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        int contentWidth = mWidgetSpacingLayout.getContentWidth();
1172038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft - mPageLayoutPaddingRight
11736a3fd3f042c8bfa7d83e29c1eeadff21323ab089Winson Chung                - ((mWidgetCountX - 1) * mWidgetWidthGap)) / mWidgetCountX);
1174038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        int contentHeight = mWidgetSpacingLayout.getContentHeight();
1175038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        final int cellHeight = ((contentHeight - mPageLayoutPaddingTop - mPageLayoutPaddingBottom
11766a3fd3f042c8bfa7d83e29c1eeadff21323ab089Winson Chung                - ((mWidgetCountY - 1) * mWidgetHeightGap)) / mWidgetCountY);
1177d294526ad99db70d882a1e11f2b0f878524163faWinson Chung
1178e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung        // Prepare the set of widgets to load previews for in the background
117939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        int offset = (page - mNumAppsPages) * numItemsPerPage;
11806a3fd3f042c8bfa7d83e29c1eeadff21323ab089Winson Chung        for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) {
11816a3fd3f042c8bfa7d83e29c1eeadff21323ab089Winson Chung            items.add(mWidgets.get(i));
1182b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        }
1183b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
1184e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung        // Prepopulate the pages with the other widget info, and fill in the previews later
118539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
1186e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung        layout.setColumnCount(layout.getCellCountX());
1187e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung        for (int i = 0; i < items.size(); ++i) {
1188e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            Object rawInfo = items.get(i);
1189e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            PendingAddItemInfo createItemInfo = null;
1190e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
1191e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                    R.layout.apps_customize_widget, layout, false);
1192e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            if (rawInfo instanceof AppWidgetProviderInfo) {
1193e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                // Fill in the widget information
1194e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
1195e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                createItemInfo = new PendingAddWidgetInfo(info, null, null);
11961f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen
11971f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                // Determine the widget spans and min resize spans.
11982f093b6ad185967c129781526060288e983bc58aAdam Cohen                int[] spanXY = Launcher.getSpanForWidget(mLauncher, info);
11991f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                createItemInfo.spanX = spanXY[0];
12001f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                createItemInfo.spanY = spanXY[1];
12012f093b6ad185967c129781526060288e983bc58aAdam Cohen                int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, info);
12021f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                createItemInfo.minSpanX = minSpanXY[0];
12031f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen                createItemInfo.minSpanY = minSpanXY[1];
12041f36270212e46b6ec0f27a0109ceaa9eb4a4995dAdam Cohen
12053f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka                widget.applyFromAppWidgetProviderInfo(info, -1, spanXY, mWidgetPreviewLoader);
1206e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                widget.setTag(createItemInfo);
1207ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                widget.setShortPressListener(this);
1208e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            } else if (rawInfo instanceof ResolveInfo) {
1209e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                // Fill in the shortcuts information
1210e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                ResolveInfo info = (ResolveInfo) rawInfo;
1211dac8591072959f69eaa8c6319311fd111ae75db6Michael Jurka                createItemInfo = new PendingAddShortcutInfo(info.activityInfo);
1212e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
1213e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
1214e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                        info.activityInfo.name);
12153f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka                widget.applyFromResolveInfo(mPackageManager, info, mWidgetPreviewLoader);
1216e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                widget.setTag(createItemInfo);
1217e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            }
1218e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            widget.setOnClickListener(this);
1219e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            widget.setOnLongClickListener(this);
1220e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            widget.setOnTouchListener(this);
1221c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung            widget.setOnKeyListener(this);
1222e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung
1223e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            // Layout each widget
1224e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            int ix = i % mWidgetCountX;
1225e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            int iy = i / mWidgetCountX;
1226e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            GridLayout.LayoutParams lp = new GridLayout.LayoutParams(
1227cc11f742586b57c576026b7756a46209fe793ea1Fabrice Di Meglio                    GridLayout.spec(iy, GridLayout.START),
1228e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung                    GridLayout.spec(ix, GridLayout.TOP));
1229e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            lp.width = cellWidth;
1230e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            lp.height = cellHeight;
1231cc11f742586b57c576026b7756a46209fe793ea1Fabrice Di Meglio            lp.setGravity(Gravity.TOP | Gravity.START);
1232e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            if (ix > 0) lp.leftMargin = mWidgetWidthGap;
1233e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            if (iy > 0) lp.topMargin = mWidgetHeightGap;
1234e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung            layout.addView(widget, lp);
1235e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung        }
1236e4a647f8793ce7823394db43d6af57f9eab8a340Winson Chung
1237038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        // wait until a call on onLayout to start loading, because
1238038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        // PagedViewWidget.getPreviewSize() will return 0 if it hasn't been laid out
1239038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        // TODO: can we do a measure/layout immediately?
1240038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        layout.setOnLayoutListener(new Runnable() {
1241038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka            public void run() {
1242038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                // Load the widget previews
1243038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                int maxPreviewWidth = cellWidth;
1244038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                int maxPreviewHeight = cellHeight;
1245038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                if (layout.getChildCount() > 0) {
1246038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    PagedViewWidget w = (PagedViewWidget) layout.getChildAt(0);
1247038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    int[] maxSize = w.getPreviewSize();
1248038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    maxPreviewWidth = maxSize[0];
1249038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    maxPreviewHeight = maxSize[1];
1250038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                }
125105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka
12523f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka                mWidgetPreviewLoader.setPreviewSize(
12533f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka                        maxPreviewWidth, maxPreviewHeight, mWidgetSpacingLayout);
1254038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                if (immediate) {
1255038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    AsyncTaskPageData data = new AsyncTaskPageData(page, items,
12563f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka                            maxPreviewWidth, maxPreviewHeight, null, null, mWidgetPreviewLoader);
1257038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    loadWidgetPreviewsInBackground(null, data);
1258038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                    onSyncWidgetPageItems(data);
1259038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                } else {
1260f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka                    if (mInTransition) {
1261f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka                        mDeferredPrepareLoadWidgetPreviewsTasks.add(this);
1262f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka                    } else {
1263f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka                        prepareLoadWidgetPreviewsTask(page, items,
1264f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka                                maxPreviewWidth, maxPreviewHeight, mWidgetCountX);
1265f6a9690c3471a8114250f10d8c7c0f22f43ffb8bMichael Jurka                    }
1266038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka                }
12673c69decd81c9ae964849e998fae6d22a505e4368Michael Jurka                layout.setOnLayoutListener(null);
1268038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka            }
1269038f9d8bfb53288e7cf5812f62ec3d5b25fec965Michael Jurka        });
1270f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung    }
1271f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung    private void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task,
1272f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            AsyncTaskPageData data) {
127368e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // loadWidgetPreviewsInBackground can be called without a task to load a set of widget
127468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        // previews synchronously
1275f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        if (task != null) {
1276f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            // Ensure that this task starts running at the correct priority
1277f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            task.syncThreadPriority();
1278f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        }
1279f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung
1280f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        // Load each of the widget/shortcut previews
1281f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        ArrayList<Object> items = data.items;
1282f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        ArrayList<Bitmap> images = data.generatedImages;
1283f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        int count = items.size();
1284f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        for (int i = 0; i < count; ++i) {
1285f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            if (task != null) {
1286f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung                // Ensure we haven't been cancelled yet
1287f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung                if (task.isCancelled()) break;
1288f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung                // Before work on each item, ensure that this task is running at the correct
1289f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung                // priority
1290f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung                task.syncThreadPriority();
1291f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            }
1292f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung
129305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka            images.add(mWidgetPreviewLoader.getPreview(items.get(i)));
1294f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung        }
1295b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
1296b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
129739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka    private void onSyncWidgetPageItems(AsyncTaskPageData data) {
129839e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        if (mInTransition) {
129939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            mDeferredSyncWidgetPageItems.add(data);
130039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            return;
130146af2e89164b391b7a0049c6ce9048a2b7a7f644Winson Chung        }
130239e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        try {
130339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            int page = data.page;
130439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
130539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka
130639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            ArrayList<Object> items = data.items;
130739e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            int count = items.size();
130839e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            for (int i = 0; i < count; ++i) {
130939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                PagedViewWidget widget = (PagedViewWidget) layout.getChildAt(i);
131039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                if (widget != null) {
131139e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                    Bitmap preview = data.generatedImages.get(i);
131239e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                    widget.applyPreview(new FastBitmapDrawable(preview), i);
131339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                }
131439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            }
1315b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung
131647639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            enableHwLayersOnVisiblePages();
131768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung
131839e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            // Update all thread priorities
131939e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
132039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            while (iter.hasNext()) {
132139e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
132239e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                int pageIndex = task.page;
132339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka                task.setThreadPriority(getThreadPriorityForPage(pageIndex));
132439e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            }
132539e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        } finally {
132639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            data.cleanup(false);
132768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        }
1328b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
132946af2e89164b391b7a0049c6ce9048a2b7a7f644Winson Chung
1330785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    @Override
1331785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void syncPages() {
1332785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        removeAllViews();
13330cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        cancelAllTasks();
1334875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung
13350cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        Context context = getContext();
13360cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        for (int j = 0; j < mNumWidgetPages; ++j) {
13370cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
13380cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                    mWidgetCountY);
13390cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            setupPage(layout);
134039e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
13410cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen                    LayoutParams.MATCH_PARENT));
1342875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung        }
1343875de7e1605f4fc8f04c804b5ac4bb9386189630Winson Chung
13440cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        for (int i = 0; i < mNumAppsPages; ++i) {
13450cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            PagedViewCellLayout layout = new PagedViewCellLayout(context);
13460cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            setupPage(layout);
13470cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            addView(layout);
1348785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1349785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
13500cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
1351785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    @Override
1352f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung    public void syncPageItems(int page, boolean immediate) {
13530cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        if (page < mNumAppsPages) {
1354f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            syncAppsPageItems(page, immediate);
13550cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        } else {
135639e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka            syncWidgetPageItems(page, immediate);
1357785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1358785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1359785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
136022f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    // We want our pages to be z-ordered such that the further a page is to the left, the higher
136122f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    // it is in the z-order. This is important to insure touch events are handled correctly.
136222f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    View getPageAt(int index) {
136339e5d176e6e375e7ae46d42ed14412d54cb223c9Michael Jurka        return getChildAt(indexToPage(index));
136422f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    }
136522f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
1366ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    @Override
1367ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    protected int indexToPage(int index) {
1368ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        return getChildCount() - index - 1;
1369ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    }
1370ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen
137122f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
137222f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    @Override
137322f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    protected void screenScrolled(int screenCenter) {
137452aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung        final boolean isRtl = isLayoutRtl();
137522f823d340710bcde587b18a1542570cbe0360f5Adam Cohen        super.screenScrolled(screenCenter);
137622f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
137722f823d340710bcde587b18a1542570cbe0360f5Adam Cohen        for (int i = 0; i < getChildCount(); i++) {
137822f823d340710bcde587b18a1542570cbe0360f5Adam Cohen            View v = getPageAt(i);
137922f823d340710bcde587b18a1542570cbe0360f5Adam Cohen            if (v != null) {
1380b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                float scrollProgress = getScrollProgress(screenCenter, v, i);
138122f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
138252aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                float interpolatedProgress;
138352aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                float translationX;
138452aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                float maxScrollProgress = Math.max(0, scrollProgress);
138552aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                float minScrollProgress = Math.min(0, scrollProgress);
138652aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung
138752aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                if (isRtl) {
138852aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    translationX = maxScrollProgress * v.getMeasuredWidth();
138952aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(maxScrollProgress));
139052aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                } else {
139152aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    translationX = minScrollProgress * v.getMeasuredWidth();
139252aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress));
139352aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                }
139422f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                float scale = (1 - interpolatedProgress) +
139522f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                        interpolatedProgress * TRANSITION_SCALE_FACTOR;
1396b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
13972591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohen                float alpha;
139852aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                if (isRtl && (scrollProgress > 0)) {
139952aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(maxScrollProgress));
140052aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                } else if (!isRtl && (scrollProgress < 0)) {
140152aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));
14022591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohen                } else {
140352aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    //  On large screens we need to fade the page as it nears its leftmost position
14042591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohen                    alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
14052591f6a5202664faf8cde2b68361e3842ce76ba9Adam Cohen                }
140622f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
140722f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                v.setCameraDistance(mDensity * CAMERA_DISTANCE);
140822f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                int pageWidth = v.getMeasuredWidth();
140922f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                int pageHeight = v.getMeasuredHeight();
1410b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
1411b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                if (PERFORM_OVERSCROLL_ROTATION) {
141252aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    float xPivot = isRtl ? 1f - TRANSITION_PIVOT : TRANSITION_PIVOT;
141352aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    boolean isOverscrollingFirstPage = isRtl ? scrollProgress > 0 : scrollProgress < 0;
141452aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    boolean isOverscrollingLastPage = isRtl ? scrollProgress < 0 : scrollProgress > 0;
141552aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung
141652aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    if (i == 0 && isOverscrollingFirstPage) {
1417b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        // Overscroll to the left
141852aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                        v.setPivotX(xPivot * pageWidth);
1419b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
1420b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        scale = 1.0f;
1421b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        alpha = 1.0f;
1422b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        // On the first page, we don't want the page to have any lateral motion
1423ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen                        translationX = 0;
142452aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                    } else if (i == getChildCount() - 1 && isOverscrollingLastPage) {
1425b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        // Overscroll to the right
142652aee60edcfe5a16e16523c1a4241ac4d8b3672dWinson Chung                        v.setPivotX((1 - xPivot) * pageWidth);
1427b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
1428b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        scale = 1.0f;
1429b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        alpha = 1.0f;
1430b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        // On the last page, we don't want the page to have any lateral motion.
1431ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen                        translationX = 0;
1432b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                    } else {
1433b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        v.setPivotY(pageHeight / 2.0f);
1434b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        v.setPivotX(pageWidth / 2.0f);
1435b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                        v.setRotationY(0f);
1436b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                    }
143722f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                }
143822f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
143922f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                v.setTranslationX(translationX);
144022f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                v.setScaleX(scale);
144122f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                v.setScaleY(scale);
144222f823d340710bcde587b18a1542570cbe0360f5Adam Cohen                v.setAlpha(alpha);
14434e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen
14444e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen                // If the view has 0 alpha, we set it to be invisible so as to prevent
14454e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen                // it from accepting touches
14468b805b17158886035b38261eb611d8641701ae43Michael Jurka                if (alpha == 0) {
14474e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen                    v.setVisibility(INVISIBLE);
14484e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen                } else if (v.getVisibility() != VISIBLE) {
14494e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen                    v.setVisibility(VISIBLE);
14504e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen                }
145122f823d340710bcde587b18a1542570cbe0360f5Adam Cohen            }
145222f823d340710bcde587b18a1542570cbe0360f5Adam Cohen        }
145347639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka
145447639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        enableHwLayersOnVisiblePages();
145547639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka    }
145647639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka
145747639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka    private void enableHwLayersOnVisiblePages() {
145847639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        final int screenCount = getChildCount();
145947639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka
146047639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        getVisiblePages(mTempVisiblePagesRange);
146147639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        int leftScreen = mTempVisiblePagesRange[0];
146247639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        int rightScreen = mTempVisiblePagesRange[1];
146347639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        int forceDrawScreen = -1;
146447639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        if (leftScreen == rightScreen) {
146547639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            // make sure we're caching at least two pages always
146647639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            if (rightScreen < screenCount - 1) {
146747639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                rightScreen++;
146847639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                forceDrawScreen = rightScreen;
146947639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            } else if (leftScreen > 0) {
147047639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                leftScreen--;
147147639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                forceDrawScreen = leftScreen;
147247639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            }
147347639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        } else {
147447639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            forceDrawScreen = leftScreen + 1;
147547639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        }
147647639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka
147747639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        for (int i = 0; i < screenCount; i++) {
147847639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            final View layout = (View) getPageAt(i);
147947639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            if (!(leftScreen <= i && i <= rightScreen &&
148047639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                    (i == forceDrawScreen || shouldDrawChild(layout)))) {
148147639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                layout.setLayerType(LAYER_TYPE_NONE, null);
148247639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            }
148347639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        }
148447639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka
148547639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        for (int i = 0; i < screenCount; i++) {
148647639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            final View layout = (View) getPageAt(i);
148747639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka
148847639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            if (leftScreen <= i && i <= rightScreen &&
148947639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                    (i == forceDrawScreen || shouldDrawChild(layout))) {
149047639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                if (layout.getLayerType() != LAYER_TYPE_HARDWARE) {
149147639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                    layout.setLayerType(LAYER_TYPE_HARDWARE, null);
149247639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka                }
149347639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka            }
149447639b9c1db9a5d0d89ce6b4b36d6b3c0d489602Michael Jurka        }
149522f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    }
149622f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
149722f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    protected void overScroll(float amount) {
1498cff6af81d721415785bddc2efd74e179d2def9daAdam Cohen        acceleratedOverScroll(amount);
149922f823d340710bcde587b18a1542570cbe0360f5Adam Cohen    }
150022f823d340710bcde587b18a1542570cbe0360f5Adam Cohen
1501785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    /**
1502785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * Used by the parent to get the content width to set the tab bar to
1503785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * @return
1504785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     */
1505785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public int getPageContentWidth() {
1506785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        return mContentWidth;
1507785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1508785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung
1509b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung    @Override
1510b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung    protected void onPageEndMoving() {
1511b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        super.onPageEndMoving();
15125e368ffbad2fb08e3eadab98eeefd4e1d05bdb2bMichael Jurka        mForceDrawAllChildrenNextFrame = true;
15135afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        // We reset the save index when we change pages so that it will be recalculated on next
15145afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        // rotation
15155afbf7bdd6f6879124c9b8283e005fe57f310d02Winson Chung        mSaveInstanceStateItemIndex = -1;
1516b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung    }
1517b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
1518785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    /*
1519785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     * AllAppsView implementation
1520785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung     */
1521785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void setup(Launcher launcher, DragController dragController) {
1522785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        mLauncher = launcher;
1523785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        mDragController = dragController;
1524785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
15259802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung
15269802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung    /**
15279802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung     * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
15289802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung     * appropriately determine when to invalidate the PagedView page data.  In cases where the data
15299802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung     * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
15309802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung     * next onMeasure() pass, which will trigger an invalidatePageData() itself.
15319802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung     */
15329802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung    private void invalidateOnDataChange() {
15339802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung        if (!isDataReady()) {
15349802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung            // The next layout pass will trigger data-ready if both widgets and apps are set, so
15359802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung            // request a layout to trigger the page data when ready.
15369802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung            requestLayout();
15379802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung        } else {
15389802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung            cancelAllTasks();
15399802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung            invalidatePageData();
15409802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung        }
15419802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung    }
15429802ac9024b7bef300c6c9eb46aa63eb04697b28Winson Chung
1543785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void setApps(ArrayList<ApplicationInfo> list) {
1544785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        mApps = list;
15451190487e15325e371c6c18181b1a5ef7ab2a79e6Winson Chung        Collections.sort(mApps, LauncherModel.getAppNameComparator());
1546c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        updatePageCountsAndInvalidateData();
1547785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1548374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani
1549785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
1550785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // We add it in place, in alphabetical order
1551785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int count = list.size();
1552785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        for (int i = 0; i < count; ++i) {
1553785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            ApplicationInfo info = list.get(i);
15541190487e15325e371c6c18181b1a5ef7ab2a79e6Winson Chung            int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator());
1555785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            if (index < 0) {
1556785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                mApps.add(-(index + 1), info);
1557785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            }
1558785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1559785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1560785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void addApps(ArrayList<ApplicationInfo> list) {
1561785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        addAppsWithoutInvalidate(list);
1562c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        updatePageCountsAndInvalidateData();
1563785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1564785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
1565785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        ComponentName removeComponent = item.intent.getComponent();
1566785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int length = list.size();
1567785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        for (int i = 0; i < length; ++i) {
1568785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            ApplicationInfo info = list.get(i);
1569374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani            if (info.user.equals(item.user)
1570374753cabf05cde1ad669d07bde47e34fdcbe499Amith Yamasani                    && info.intent.getComponent().equals(removeComponent)) {
1571785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                return i;
1572785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            }
1573785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1574785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        return -1;
1575785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1576785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
1577785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // loop through all the apps and remove apps that have the same component
1578785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        int length = list.size();
1579785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        for (int i = 0; i < length; ++i) {
1580785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            ApplicationInfo info = list.get(i);
1581785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            int removeIndex = findAppByComponent(mApps, info);
1582785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            if (removeIndex > -1) {
1583785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                mApps.remove(removeIndex);
1584785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung            }
1585785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1586785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
158783892cc0768bd6d7f0827886e9e7a2eb3eed2b01Winson Chung    public void removeApps(ArrayList<ApplicationInfo> appInfos) {
158883892cc0768bd6d7f0827886e9e7a2eb3eed2b01Winson Chung        removeAppsWithoutInvalidate(appInfos);
1589c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        updatePageCountsAndInvalidateData();
1590785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1591785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void updateApps(ArrayList<ApplicationInfo> list) {
1592785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // We remove and re-add the updated applications list because it's properties may have
1593785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // changed (ie. the title), and this will ensure that the items will be in their proper
1594785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // place in the list.
1595785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        removeAppsWithoutInvalidate(list);
1596785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        addAppsWithoutInvalidate(list);
1597c402cd9992d431b6beacdf3c75e31cf103e230cbMichael Jurka        updatePageCountsAndInvalidateData();
1598785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
159935aa14d5e33e4f5cccb9fd23be1047f26d67b409Michael Jurka
1600785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void reset() {
1601649668f7af9ef730466082f935831c901cafc74aWinson Chung        // If we have reset, then we should not continue to restore the previous state
1602649668f7af9ef730466082f935831c901cafc74aWinson Chung        mSaveInstanceStateItemIndex = -1;
1603649668f7af9ef730466082f935831c901cafc74aWinson Chung
1604b64d36e6f8006b3ea5a6c2951af4cf8dea72d08eAdam Cohen        AppsCustomizeTabHost tabHost = getTabHost();
1605b64d36e6f8006b3ea5a6c2951af4cf8dea72d08eAdam Cohen        String tag = tabHost.getCurrentTabTag();
16066a8103c7efcaf6ea6e3170b36bf96dcfc1fa36b3Winson Chung        if (tag != null) {
16076a8103c7efcaf6ea6e3170b36bf96dcfc1fa36b3Winson Chung            if (!tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) {
16086a8103c7efcaf6ea6e3170b36bf96dcfc1fa36b3Winson Chung                tabHost.setCurrentTabFromContent(ContentType.Applications);
16096a8103c7efcaf6ea6e3170b36bf96dcfc1fa36b3Winson Chung            }
1610b64d36e6f8006b3ea5a6c2951af4cf8dea72d08eAdam Cohen        }
1611649668f7af9ef730466082f935831c901cafc74aWinson Chung
1612b64d36e6f8006b3ea5a6c2951af4cf8dea72d08eAdam Cohen        if (mCurrentPage != 0) {
1613b64d36e6f8006b3ea5a6c2951af4cf8dea72d08eAdam Cohen            invalidatePageData(0);
1614b64d36e6f8006b3ea5a6c2951af4cf8dea72d08eAdam Cohen        }
16150cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    }
16160cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
16170cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen    private AppsCustomizeTabHost getTabHost() {
16180cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane);
1619785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
16200cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
1621785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void dumpState() {
1622785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // TODO: Dump information related to current list of Applications, Widgets, etc.
16230e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
16240e56cc9fd6814af5813e73ba7a71bf1d51d4208aAdam Cohen        dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
1625785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
16264e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen
1627785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    private void dumpAppWidgetProviderInfoList(String tag, String label,
1628d294526ad99db70d882a1e11f2b0f878524163faWinson Chung            ArrayList<Object> list) {
1629785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        Log.d(tag, label + " size=" + list.size());
16301ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung        for (Object i: list) {
16311ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung            if (i instanceof AppWidgetProviderInfo) {
16321ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                AppWidgetProviderInfo info = (AppWidgetProviderInfo) i;
16331ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                Log.d(tag, "   label=\"" + info.label + "\" previewImage=" + info.previewImage
16341ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                        + " resizeMode=" + info.resizeMode + " configure=" + info.configure
16351ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                        + " initialLayout=" + info.initialLayout
16361ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                        + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight);
16371ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung            } else if (i instanceof ResolveInfo) {
16381ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                ResolveInfo info = (ResolveInfo) i;
16391ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                Log.d(tag, "   label=\"" + info.loadLabel(mPackageManager) + "\" icon="
16401ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung                        + info.icon);
16411ed747a4c07101793322c13a36dd547df4a3aa50Winson Chung            }
1642785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        }
1643785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
16444e84401aa8f7c724190ffd2898d2eb939c019e82Adam Cohen
1645785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    public void surrender() {
1646785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
1647785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        // should stop this now.
16484b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung
16494b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung        // Stop all background tasks
16504b0ed8c09ebc6afd97ff8b0de6a9617f6469ad1aWinson Chung        cancelAllTasks();
1651785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    }
1652007c69867d821ea2b271398577a8b3440b3a7046Winson Chung
1653e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung    @Override
1654e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung    public void iconPressed(PagedViewIcon icon) {
1655e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        // Reset the previously pressed icon and store a reference to the pressed icon so that
1656e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        // we can reset it on return to Launcher (in Launcher.onResume())
1657e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        if (mPressedIcon != null) {
1658e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung            mPressedIcon.resetDrawableState();
1659e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        }
1660e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        mPressedIcon = icon;
1661e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung    }
1662e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung
1663e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung    public void resetDrawableState() {
1664e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        if (mPressedIcon != null) {
1665e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung            mPressedIcon.resetDrawableState();
1666e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung            mPressedIcon = null;
1667e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung        }
1668e4e506660ba93ae2c4f1cb0b41378cf148c85e2bWinson Chung    }
166968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung
1670b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    /*
1671b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     * We load an extra page on each side to prevent flashes from scrolling and loading of the
1672b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     * widget previews in the background with the AsyncTasks.
1673b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung     */
167468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung    final static int sLookBehindPageCount = 2;
167568e4c64a67f4a40afac4cab44def461783f096a4Winson Chung    final static int sLookAheadPageCount = 2;
1676b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    protected int getAssociatedLowerPageBound(int page) {
167768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        final int count = getChildCount();
167868e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
167968e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0);
168068e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        return windowMinIndex;
1681b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
1682b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    protected int getAssociatedUpperPageBound(int page) {
1683b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung        final int count = getChildCount();
168468e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
168568e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1),
168668e4c64a67f4a40afac4cab44def461783f096a4Winson Chung                count - 1);
168768e4c64a67f4a40afac4cab44def461783f096a4Winson Chung        return windowMaxIndex;
1688b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung    }
16896a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung
16906a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung    @Override
16916a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung    protected String getCurrentPageDescription() {
16926a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
16936a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        int stringId = R.string.default_scroll_format;
1694d3357b186d55816e682b3012cfccd2d7a0680678Adam Cohen        int count = 0;
1695d3357b186d55816e682b3012cfccd2d7a0680678Adam Cohen
16960cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        if (page < mNumAppsPages) {
16976a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung            stringId = R.string.apps_customize_apps_scroll_format;
1698d3357b186d55816e682b3012cfccd2d7a0680678Adam Cohen            count = mNumAppsPages;
16990cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen        } else {
17000cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen            page -= mNumAppsPages;
17016a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung            stringId = R.string.apps_customize_widgets_scroll_format;
1702d3357b186d55816e682b3012cfccd2d7a0680678Adam Cohen            count = mNumWidgetPages;
17036a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        }
17040cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen
17058b805b17158886035b38261eb611d8641701ae43Michael Jurka        return String.format(getContext().getString(stringId), page + 1, count);
17066a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung    }
1707785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung}
1708