1 /* 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 17 package com.android.launcher2; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.graphics.drawable.BitmapDrawable; 23 import android.graphics.Bitmap; 24 import android.graphics.Color; 25 import android.util.AttributeSet; 26 import android.util.Log; 27 import android.view.KeyEvent; 28 import android.view.ViewGroup; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.animation.AnimationUtils; 32 import android.view.ViewConfiguration; 33 import android.widget.AdapterView; 34 import android.widget.ImageButton; 35 import android.widget.TextView; 36 import android.widget.ArrayAdapter; 37 import android.widget.GridView; 38 import android.widget.RelativeLayout; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 43 import com.android.launcher.R; 44 45 public class AllApps2D 46 extends RelativeLayout 47 implements AllAppsView, 48 AdapterView.OnItemClickListener, 49 AdapterView.OnItemLongClickListener, 50 View.OnKeyListener, 51 DragSource { 52 53 private static final String TAG = "Launcher.AllApps2D"; 54 private static final boolean DEBUG = false; 55 56 private Launcher mLauncher; 57 private DragController mDragController; 58 59 private GridView mGrid; 60 61 private ArrayList<ApplicationInfo> mAllAppsList = new ArrayList<ApplicationInfo>(); 62 63 // preserve compatibility with 3D all apps: 64 // 0.0 -> hidden 65 // 1.0 -> shown and opaque 66 // intermediate values -> partially shown & partially opaque 67 private float mZoom; 68 69 private AppsAdapter mAppsAdapter; 70 71 // ------------------------------------------------------------ 72 73 public static class HomeButton extends ImageButton { 74 public HomeButton(Context context, AttributeSet attrs) { 75 super(context, attrs); 76 } 77 @Override 78 public View focusSearch(int direction) { 79 if (direction == FOCUS_UP) return super.focusSearch(direction); 80 return null; 81 } 82 } 83 84 public class AppsAdapter extends ArrayAdapter<ApplicationInfo> { 85 private final LayoutInflater mInflater; 86 87 public AppsAdapter(Context context, ArrayList<ApplicationInfo> apps) { 88 super(context, 0, apps); 89 mInflater = LayoutInflater.from(context); 90 } 91 92 @Override 93 public View getView(int position, View convertView, ViewGroup parent) { 94 final ApplicationInfo info = getItem(position); 95 96 if (convertView == null) { 97 convertView = mInflater.inflate(R.layout.application_boxed, parent, false); 98 } 99 100 // if (!info.filtered) { 101 // info.icon = Utilities.createIconThumbnail(info.icon, getContext()); 102 // info.filtered = true; 103 // } 104 105 final TextView textView = (TextView) convertView; 106 if (DEBUG) { 107 Log.d(TAG, "icon bitmap = " + info.iconBitmap 108 + " density = " + info.iconBitmap.getDensity()); 109 } 110 info.iconBitmap.setDensity(Bitmap.DENSITY_NONE); 111 textView.setCompoundDrawablesWithIntrinsicBounds(null, new BitmapDrawable(info.iconBitmap), null, null); 112 textView.setText(info.title); 113 114 return convertView; 115 } 116 } 117 118 public AllApps2D(Context context, AttributeSet attrs) { 119 super(context, attrs); 120 setVisibility(View.GONE); 121 setSoundEffectsEnabled(false); 122 123 mAppsAdapter = new AppsAdapter(getContext(), mAllAppsList); 124 mAppsAdapter.setNotifyOnChange(false); 125 } 126 127 @Override 128 protected void onFinishInflate() { 129 setBackgroundColor(Color.BLACK); 130 131 try { 132 mGrid = (GridView)findViewWithTag("all_apps_2d_grid"); 133 if (mGrid == null) throw new Resources.NotFoundException(); 134 mGrid.setOnItemClickListener(this); 135 mGrid.setOnItemLongClickListener(this); 136 mGrid.setBackgroundColor(Color.BLACK); 137 mGrid.setCacheColorHint(Color.BLACK); 138 139 ImageButton homeButton = (ImageButton) findViewWithTag("all_apps_2d_home"); 140 if (homeButton == null) throw new Resources.NotFoundException(); 141 homeButton.setOnClickListener( 142 new View.OnClickListener() { 143 public void onClick(View v) { 144 mLauncher.closeAllApps(true); 145 } 146 }); 147 } catch (Resources.NotFoundException e) { 148 Log.e(TAG, "Can't find necessary layout elements for AllApps2D"); 149 } 150 151 setOnKeyListener(this); 152 } 153 154 public AllApps2D(Context context, AttributeSet attrs, int defStyle) { 155 this(context, attrs); 156 } 157 158 public void setLauncher(Launcher launcher) { 159 mLauncher = launcher; 160 } 161 162 public boolean onKey(View v, int keyCode, KeyEvent event) { 163 if (!isVisible()) return false; 164 165 switch (keyCode) { 166 case KeyEvent.KEYCODE_BACK: 167 mLauncher.closeAllApps(true); 168 break; 169 default: 170 return false; 171 } 172 173 return true; 174 } 175 176 public void onItemClick(AdapterView parent, View v, int position, long id) { 177 ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); 178 mLauncher.startActivitySafely(app.intent, app); 179 } 180 181 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 182 if (!view.isInTouchMode()) { 183 return false; 184 } 185 186 ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); 187 app = new ApplicationInfo(app); 188 189 mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); 190 mLauncher.closeAllApps(true); 191 192 return true; 193 } 194 195 protected void onFocusChanged(boolean gainFocus, int direction, android.graphics.Rect prev) { 196 if (gainFocus) { 197 mGrid.requestFocus(); 198 } 199 } 200 201 public void setDragController(DragController dragger) { 202 mDragController = dragger; 203 } 204 205 public void onDropCompleted(View target, boolean success) { 206 } 207 208 /** 209 * Zoom to the specifed level. 210 * 211 * @param zoom [0..1] 0 is hidden, 1 is open 212 */ 213 public void zoom(float zoom, boolean animate) { 214 // Log.d(TAG, "zooming " + ((zoom == 1.0) ? "open" : "closed")); 215 cancelLongPress(); 216 217 mZoom = zoom; 218 219 if (isVisible()) { 220 getParent().bringChildToFront(this); 221 setVisibility(View.VISIBLE); 222 mGrid.setAdapter(mAppsAdapter); 223 if (animate) { 224 startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_in)); 225 } else { 226 onAnimationEnd(); 227 } 228 } else { 229 if (animate) { 230 startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_out)); 231 } else { 232 onAnimationEnd(); 233 } 234 } 235 } 236 237 protected void onAnimationEnd() { 238 if (!isVisible()) { 239 setVisibility(View.GONE); 240 mGrid.setAdapter(null); 241 mZoom = 0.0f; 242 } else { 243 mZoom = 1.0f; 244 } 245 246 mLauncher.zoomed(mZoom); 247 } 248 249 public boolean isVisible() { 250 return mZoom > 0.001f; 251 } 252 253 @Override 254 public boolean isOpaque() { 255 return mZoom > 0.999f; 256 } 257 258 public void setApps(ArrayList<ApplicationInfo> list) { 259 mAllAppsList.clear(); 260 addApps(list); 261 } 262 263 public void addApps(ArrayList<ApplicationInfo> list) { 264 // Log.d(TAG, "addApps: " + list.size() + " apps: " + list.toString()); 265 266 final int N = list.size(); 267 268 for (int i=0; i<N; i++) { 269 final ApplicationInfo item = list.get(i); 270 int index = Collections.binarySearch(mAllAppsList, item, 271 LauncherModel.APP_NAME_COMPARATOR); 272 if (index < 0) { 273 index = -(index+1); 274 } 275 mAllAppsList.add(index, item); 276 } 277 mAppsAdapter.notifyDataSetChanged(); 278 } 279 280 public void removeApps(ArrayList<ApplicationInfo> list) { 281 final int N = list.size(); 282 for (int i=0; i<N; i++) { 283 final ApplicationInfo item = list.get(i); 284 int index = findAppByComponent(mAllAppsList, item); 285 if (index >= 0) { 286 mAllAppsList.remove(index); 287 } else { 288 Log.w(TAG, "couldn't find a match for item \"" + item + "\""); 289 // Try to recover. This should keep us from crashing for now. 290 } 291 } 292 mAppsAdapter.notifyDataSetChanged(); 293 } 294 295 public void updateApps(ArrayList<ApplicationInfo> list) { 296 // Just remove and add, because they may need to be re-sorted. 297 removeApps(list); 298 addApps(list); 299 } 300 301 private static int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) { 302 ComponentName component = item.intent.getComponent(); 303 final int N = list.size(); 304 for (int i=0; i<N; i++) { 305 ApplicationInfo x = list.get(i); 306 if (x.intent.getComponent().equals(component)) { 307 return i; 308 } 309 } 310 return -1; 311 } 312 313 public void dumpState() { 314 ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList", mAllAppsList); 315 } 316 317 public void surrender() { 318 } 319 } 320 321 322