blob: 0bb4ee95fe30980e4b6a005c960287d0612c7b53 [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;
Daniel Sandler388f6792010-03-02 14:08:08 -050022import android.graphics.drawable.BitmapDrawable;
Daniel Sandler388f6792010-03-02 14:08:08 -050023import android.util.AttributeSet;
24import android.util.Log;
25import android.view.KeyEvent;
26import android.view.ViewGroup;
Daniel Sandler388f6792010-03-02 14:08:08 -050027import android.view.LayoutInflater;
Daniel Sandler388f6792010-03-02 14:08:08 -050028import android.view.View;
Daniel Sandler388f6792010-03-02 14:08:08 -050029import android.view.animation.AnimationUtils;
30import android.view.ViewConfiguration;
Daniel Sandler388f6792010-03-02 14:08:08 -050031import android.widget.AdapterView;
32import android.widget.ImageButton;
33import android.widget.TextView;
34import android.widget.ArrayAdapter;
35import android.widget.GridView;
36import android.widget.RelativeLayout;
37
38import java.util.ArrayList;
Daniel Sandler388f6792010-03-02 14:08:08 -050039import java.util.Collections;
Daniel Sandler388f6792010-03-02 14:08:08 -050040
Romain Guyedcce092010-03-04 13:03:17 -080041import com.android.launcher.R;
Daniel Sandler388f6792010-03-02 14:08:08 -050042
43public class AllApps2D
44 extends RelativeLayout
45 implements AllAppsView,
46 AdapterView.OnItemClickListener,
47 AdapterView.OnItemLongClickListener,
48 View.OnKeyListener,
49 DragSource {
50
51 private static final String TAG = "Launcher.AllApps2D";
52
53 private Launcher mLauncher;
54 private DragController mDragController;
55
56 private GridView mGrid;
57
58 private ArrayList<ApplicationInfo> mAllAppsList = new ArrayList<ApplicationInfo>();
59
60 /**
61 * True when we are using arrow keys or trackball to drive navigation
62 */
63 private boolean mArrowNavigation = false;
64 private boolean mStartedScrolling;
65
66 /**
67 * Used to keep track of the selection when AllApps2D loses window focus.
68 * One of the SELECTION_ constants.
69 */
70 private int mLastSelection;
71
72 /**
73 * Used to keep track of the selection when AllApps2D loses window focus
74 */
75 private int mLastSelectedIcon;
76
77 private float mZoom;
78
79 private AppsAdapter mAppsAdapter;
80
81 // ------------------------------------------------------------
82
83 public class AppsAdapter extends ArrayAdapter<ApplicationInfo> {
84 private final LayoutInflater mInflater;
85
86 public AppsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
87 super(context, 0, apps);
88 mInflater = LayoutInflater.from(context);
89 }
90
91 @Override
92 public View getView(int position, View convertView, ViewGroup parent) {
93 final ApplicationInfo info = getItem(position);
94
95 if (convertView == null) {
96 convertView = mInflater.inflate(R.layout.application_boxed, parent, false);
97 }
98
99// if (!info.filtered) {
100// info.icon = Utilities.createIconThumbnail(info.icon, getContext());
101// info.filtered = true;
102// }
103
104 final TextView textView = (TextView) convertView;
105 textView.setCompoundDrawablesWithIntrinsicBounds(null, new BitmapDrawable(info.iconBitmap), null, null);
106 textView.setText(info.title);
107
108 return convertView;
109 }
110 }
111
112 public AllApps2D(Context context, AttributeSet attrs) {
113 super(context, attrs);
114 setVisibility(View.GONE);
115 setSoundEffectsEnabled(false);
116
117 mAppsAdapter = new AppsAdapter(getContext(), mAllAppsList);
118 mAppsAdapter.setNotifyOnChange(false);
119 }
120
121 @Override
122 protected void onFinishInflate() {
123 setBackgroundColor(0xFF000000);
124
Daniel Sandlerc351eb82010-03-03 15:05:19 -0500125 try {
126 mGrid = (GridView)findViewWithTag("all_apps_2d_grid");
127 if (mGrid == null) throw new Resources.NotFoundException();
128 mGrid.setOnItemClickListener(this);
129 mGrid.setOnItemLongClickListener(this);
130
131 ImageButton homeButton = (ImageButton) findViewWithTag("all_apps_2d_home");
132 if (homeButton == null) throw new Resources.NotFoundException();
133 homeButton.setOnClickListener(
134 new View.OnClickListener() {
135 public void onClick(View v) {
136 mLauncher.closeAllApps(true);
137 }
138 });
139 } catch (Resources.NotFoundException e) {
140 Log.e(TAG, "Can't find necessary layout elements for AllApps2D");
141 }
Daniel Sandler388f6792010-03-02 14:08:08 -0500142
Daniel Sandlerc351eb82010-03-03 15:05:19 -0500143 setOnKeyListener(this);
Daniel Sandler388f6792010-03-02 14:08:08 -0500144 }
145
146 public AllApps2D(Context context, AttributeSet attrs, int defStyle) {
147 this(context, attrs);
148 }
149
150 public void setLauncher(Launcher launcher) {
151 mLauncher = launcher;
152 }
153
154 public boolean onKey(View v, int keyCode, KeyEvent event) {
155 if (!isVisible()) return false;
156
157 switch (keyCode) {
158 case KeyEvent.KEYCODE_BACK:
159 mLauncher.closeAllApps(true);
160 break;
161 default:
162 return false;
163 }
164
165 return true;
166 }
167
168 public void onItemClick(AdapterView parent, View v, int position, long id) {
169 ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
170 mLauncher.startActivitySafely(app.intent);
171 }
172
173 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
174 if (!view.isInTouchMode()) {
175 return false;
176 }
177
178 ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
179 app = new ApplicationInfo(app);
180
181 mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
182 mLauncher.closeAllApps(true);
183
184 return true;
185 }
186
187
188 public void setDragController(DragController dragger) {
189 mDragController = dragger;
190 }
191
192 public void onDropCompleted(View target, boolean success) {
193 }
194
195 /**
196 * Zoom to the specifed level.
197 *
198 * @param zoom [0..1] 0 is hidden, 1 is open
199 */
200 public void zoom(float zoom, boolean animate) {
201// Log.d(TAG, "zooming " + ((zoom == 1.0) ? "open" : "closed"));
202 cancelLongPress();
203
204 mZoom = zoom;
205
206 if (isVisible()) {
207 getParent().bringChildToFront(this);
208 setVisibility(View.VISIBLE);
209 mGrid.setAdapter(mAppsAdapter);
210 if (animate) {
211 startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_in));
212 } else {
213 onAnimationEnd();
214 }
215 } else {
216 if (animate) {
217 startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_out));
218 } else {
219 onAnimationEnd();
220 }
221 }
222 }
223
224 protected void onAnimationEnd() {
225 if (!isVisible()) {
226 setVisibility(View.GONE);
227 mGrid.setAdapter(null);
228 mZoom = 0.0f;
229 } else {
230 mZoom = 1.0f;
231 }
Daniel Sandlerc351eb82010-03-03 15:05:19 -0500232
233 mLauncher.zoomed(mZoom);
Daniel Sandler388f6792010-03-02 14:08:08 -0500234 }
235
236 public boolean isVisible() {
237 return mZoom > 0.001f;
238 }
239
240 @Override
241 public boolean isOpaque() {
242 return mZoom > 0.999f;
243 }
244
245 public void setApps(ArrayList<ApplicationInfo> list) {
246 mAllAppsList.clear();
247 addApps(list);
248 }
249
250 public void addApps(ArrayList<ApplicationInfo> list) {
251// Log.d(TAG, "addApps: " + list.size() + " apps: " + list.toString());
252
253 final int N = list.size();
254
255 for (int i=0; i<N; i++) {
256 final ApplicationInfo item = list.get(i);
257 int index = Collections.binarySearch(mAllAppsList, item,
258 LauncherModel.APP_NAME_COMPARATOR);
259 if (index < 0) {
260 index = -(index+1);
261 }
262 mAllAppsList.add(index, item);
263 }
264 mAppsAdapter.notifyDataSetChanged();
265 }
266
267 public void removeApps(ArrayList<ApplicationInfo> list) {
268 final int N = list.size();
269 for (int i=0; i<N; i++) {
270 final ApplicationInfo item = list.get(i);
271 int index = findAppByComponent(mAllAppsList, item);
272 if (index >= 0) {
273 mAllAppsList.remove(index);
274 } else {
275 Log.w(TAG, "couldn't find a match for item \"" + item + "\"");
276 // Try to recover. This should keep us from crashing for now.
277 }
278 }
279 mAppsAdapter.notifyDataSetChanged();
280 }
281
Joe Onorato64e6be72010-03-05 15:05:52 -0500282 public void updateApps(ArrayList<ApplicationInfo> list) {
Daniel Sandler388f6792010-03-02 14:08:08 -0500283 // Just remove and add, because they may need to be re-sorted.
284 removeApps(list);
285 addApps(list);
286 }
287
288 private static int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
289 ComponentName component = item.intent.getComponent();
290 final int N = list.size();
291 for (int i=0; i<N; i++) {
292 ApplicationInfo x = list.get(i);
293 if (x.intent.getComponent().equals(component)) {
294 return i;
295 }
296 }
297 return -1;
298 }
299
300 public void dumpState() {
301 ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList", mAllAppsList);
302 }
303}
304
305