blob: 4c7b28c0d4cf705260ea1cd11294b2304a9de7a6 [file] [log] [blame]
Daniel Sandler388f6792010-03-02 14:08:08 -05001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.launcher2;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.res.Resources;
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.PixelFormat;
25import android.graphics.Rect;
26import android.graphics.drawable.BitmapDrawable;
27import android.os.SystemClock;
28import android.util.AttributeSet;
29import android.util.Log;
30import android.view.KeyEvent;
31import android.view.ViewGroup;
32import android.view.MotionEvent;
33import android.view.LayoutInflater;
34import android.view.SoundEffectConstants;
35import android.view.SurfaceHolder;
36import android.view.VelocityTracker;
37import android.view.View;
38import android.view.animation.Animation;
39import android.view.animation.AnimationUtils;
40import android.view.ViewConfiguration;
41import android.view.accessibility.AccessibilityEvent;
42import android.widget.AdapterView;
43import android.widget.ImageButton;
44import android.widget.TextView;
45import android.widget.ArrayAdapter;
46import android.widget.GridView;
47import android.widget.RelativeLayout;
48
49import java.util.ArrayList;
50import java.util.Arrays;
51import java.util.Collections;
52import java.util.Comparator;
53
54
55public class AllApps2D
56 extends RelativeLayout
57 implements AllAppsView,
58 AdapterView.OnItemClickListener,
59 AdapterView.OnItemLongClickListener,
60 View.OnKeyListener,
61 DragSource {
62
63 private static final String TAG = "Launcher.AllApps2D";
64
65 private Launcher mLauncher;
66 private DragController mDragController;
67
68 private GridView mGrid;
69
70 private ArrayList<ApplicationInfo> mAllAppsList = new ArrayList<ApplicationInfo>();
71
72 /**
73 * True when we are using arrow keys or trackball to drive navigation
74 */
75 private boolean mArrowNavigation = false;
76 private boolean mStartedScrolling;
77
78 /**
79 * Used to keep track of the selection when AllApps2D loses window focus.
80 * One of the SELECTION_ constants.
81 */
82 private int mLastSelection;
83
84 /**
85 * Used to keep track of the selection when AllApps2D loses window focus
86 */
87 private int mLastSelectedIcon;
88
89 private float mZoom;
90
91 private AppsAdapter mAppsAdapter;
92
93 // ------------------------------------------------------------
94
95 public class AppsAdapter extends ArrayAdapter<ApplicationInfo> {
96 private final LayoutInflater mInflater;
97
98 public AppsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
99 super(context, 0, apps);
100 mInflater = LayoutInflater.from(context);
101 }
102
103 @Override
104 public View getView(int position, View convertView, ViewGroup parent) {
105 final ApplicationInfo info = getItem(position);
106
107 if (convertView == null) {
108 convertView = mInflater.inflate(R.layout.application_boxed, parent, false);
109 }
110
111// if (!info.filtered) {
112// info.icon = Utilities.createIconThumbnail(info.icon, getContext());
113// info.filtered = true;
114// }
115
116 final TextView textView = (TextView) convertView;
117 textView.setCompoundDrawablesWithIntrinsicBounds(null, new BitmapDrawable(info.iconBitmap), null, null);
118 textView.setText(info.title);
119
120 return convertView;
121 }
122 }
123
124 public AllApps2D(Context context, AttributeSet attrs) {
125 super(context, attrs);
126 setVisibility(View.GONE);
127 setSoundEffectsEnabled(false);
128
129 mAppsAdapter = new AppsAdapter(getContext(), mAllAppsList);
130 mAppsAdapter.setNotifyOnChange(false);
131 }
132
133 @Override
134 protected void onFinishInflate() {
135 setBackgroundColor(0xFF000000);
136
137 mGrid = (GridView)findViewById(R.id.all_apps_2d_grid);
138 mGrid.setOnItemClickListener(this);
139 mGrid.setOnItemLongClickListener(this);
140
141 setOnKeyListener(this);
142
143 ImageButton homeButton = (ImageButton) findViewById(R.id.all_apps_2d_home);
144 homeButton.setOnClickListener(
145 new View.OnClickListener() {
146 public void onClick(View v) {
147 mLauncher.closeAllApps(true);
148 }
149 });
150 }
151
152 public AllApps2D(Context context, AttributeSet attrs, int defStyle) {
153 this(context, attrs);
154 }
155
156 public void setLauncher(Launcher launcher) {
157 mLauncher = launcher;
158 }
159
160 public boolean onKey(View v, int keyCode, KeyEvent event) {
161 if (!isVisible()) return false;
162
163 switch (keyCode) {
164 case KeyEvent.KEYCODE_BACK:
165 mLauncher.closeAllApps(true);
166 break;
167 default:
168 return false;
169 }
170
171 return true;
172 }
173
174 public void onItemClick(AdapterView parent, View v, int position, long id) {
175 ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
176 mLauncher.startActivitySafely(app.intent);
177 }
178
179 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
180 if (!view.isInTouchMode()) {
181 return false;
182 }
183
184 ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
185 app = new ApplicationInfo(app);
186
187 mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
188 mLauncher.closeAllApps(true);
189
190 return true;
191 }
192
193
194 public void setDragController(DragController dragger) {
195 mDragController = dragger;
196 }
197
198 public void onDropCompleted(View target, boolean success) {
199 }
200
201 /**
202 * Zoom to the specifed level.
203 *
204 * @param zoom [0..1] 0 is hidden, 1 is open
205 */
206 public void zoom(float zoom, boolean animate) {
207// Log.d(TAG, "zooming " + ((zoom == 1.0) ? "open" : "closed"));
208 cancelLongPress();
209
210 mZoom = zoom;
211
212 if (isVisible()) {
213 getParent().bringChildToFront(this);
214 setVisibility(View.VISIBLE);
215 mGrid.setAdapter(mAppsAdapter);
216 if (animate) {
217 startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_in));
218 } else {
219 onAnimationEnd();
220 }
221 } else {
222 if (animate) {
223 startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_out));
224 } else {
225 onAnimationEnd();
226 }
227 }
228 }
229
230 protected void onAnimationEnd() {
231 if (!isVisible()) {
232 setVisibility(View.GONE);
233 mGrid.setAdapter(null);
234 mZoom = 0.0f;
235 } else {
236 mZoom = 1.0f;
237 }
238 }
239
240 public boolean isVisible() {
241 return mZoom > 0.001f;
242 }
243
244 @Override
245 public boolean isOpaque() {
246 return mZoom > 0.999f;
247 }
248
249 public void setApps(ArrayList<ApplicationInfo> list) {
250 mAllAppsList.clear();
251 addApps(list);
252 }
253
254 public void addApps(ArrayList<ApplicationInfo> list) {
255// Log.d(TAG, "addApps: " + list.size() + " apps: " + list.toString());
256
257 final int N = list.size();
258
259 for (int i=0; i<N; i++) {
260 final ApplicationInfo item = list.get(i);
261 int index = Collections.binarySearch(mAllAppsList, item,
262 LauncherModel.APP_NAME_COMPARATOR);
263 if (index < 0) {
264 index = -(index+1);
265 }
266 mAllAppsList.add(index, item);
267 }
268 mAppsAdapter.notifyDataSetChanged();
269 }
270
271 public void removeApps(ArrayList<ApplicationInfo> list) {
272 final int N = list.size();
273 for (int i=0; i<N; i++) {
274 final ApplicationInfo item = list.get(i);
275 int index = findAppByComponent(mAllAppsList, item);
276 if (index >= 0) {
277 mAllAppsList.remove(index);
278 } else {
279 Log.w(TAG, "couldn't find a match for item \"" + item + "\"");
280 // Try to recover. This should keep us from crashing for now.
281 }
282 }
283 mAppsAdapter.notifyDataSetChanged();
284 }
285
286 public void updateApps(String packageName, ArrayList<ApplicationInfo> list) {
287 // Just remove and add, because they may need to be re-sorted.
288 removeApps(list);
289 addApps(list);
290 }
291
292 private static int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
293 ComponentName component = item.intent.getComponent();
294 final int N = list.size();
295 for (int i=0; i<N; i++) {
296 ApplicationInfo x = list.get(i);
297 if (x.intent.getComponent().equals(component)) {
298 return i;
299 }
300 }
301 return -1;
302 }
303
304 public void dumpState() {
305 ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList", mAllAppsList);
306 }
307}
308
309