blob: 8375bbe55849bdd811bbeeb35a9b1c2e705c9dcd [file] [log] [blame]
The Android Open Source Projectc8f00b62008-10-21 07:00:00 -07001/*
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.launcher;
18
19import android.content.ComponentName;
20import android.content.ContentResolver;
21import android.content.ContentValues;
22import android.content.Intent;
23import android.content.Context;
24import android.content.pm.ActivityInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.ResolveInfo;
27import android.content.res.Resources;
28import android.database.Cursor;
29import android.graphics.Bitmap;
30import android.graphics.BitmapFactory;
31import android.graphics.drawable.BitmapDrawable;
32import android.net.Uri;
33import com.android.internal.provider.Settings;
34import android.util.Log;
35
36import java.util.ArrayList;
37import java.util.Collections;
38import java.util.HashMap;
39import java.util.List;
40import java.util.Comparator;
41import java.lang.ref.WeakReference;
42import java.text.Collator;
43
44/**
45 * Maintains in-memory state of the Launcher. It is expected that there should be only one
46 * LauncherModel object held in a static. Also provide APIs for updating the database state
47 * for the Launcher
48 *
49 */
50public class LauncherModel {
51 private static final int UI_NOTIFICATION_RATE = 4;
52 private static final int DEFAULT_APPLICATIONS_NUMBER = 42;
53 private static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000;
54
55 private final Collator sCollator = Collator.getInstance();
56
57 private boolean mApplicationsLoaded;
58 private boolean mDesktopItemsLoaded;
59
60 private ArrayList<ItemInfo> mDesktopItems;
61 private HashMap<Long, UserFolderInfo> mUserFolders;
62
63 private ArrayList<ApplicationInfo> mApplications;
64 private ApplicationsAdapter mApplicationsAdapter;
65 private ApplicationsLoader mApplicationsLoader;
66 private DesktopItemsLoader mDesktopItemsLoader;
67 private Thread mLoader;
68 private Thread mDesktopLoader;
69
70 void abortLoaders() {
71 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
72 mApplicationsLoader.stop();
73 mApplicationsLoaded = false;
74 }
75 if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
76 mDesktopItemsLoader.stop();
77 mDesktopItemsLoaded = false;
78 }
79 }
80
81 /**
82 * Loads the list of installed applications in mApplications.
83 */
84 void loadApplications(boolean isLaunching, Launcher launcher) {
85 if (isLaunching && mApplicationsLoaded) {
86 mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
87 return;
88 }
89
90 if (mApplicationsAdapter == null || isLaunching) {
91 mApplicationsAdapter = new ApplicationsAdapter(launcher,
92 mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER));
93 }
94
95 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
96 mApplicationsLoader.stop();
97 // Wait for the currently running thread to finish, this can take a little
98 // time but it should be well below the timeout limit
99 try {
100 mLoader.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
101 } catch (InterruptedException e) {
102 // Empty
103 }
104 }
105
106 mApplicationsLoaded = false;
107 mApplicationsLoader = new ApplicationsLoader(launcher);
108 mLoader = new Thread(mApplicationsLoader, "Applications Loader");
109 mLoader.start();
110 }
111
112 private class ApplicationsLoader implements Runnable {
113 private final WeakReference<Launcher> mLauncher;
114
115 private volatile boolean mStopped;
116 private volatile boolean mRunning;
117
118 ApplicationsLoader(Launcher launcher) {
119 mLauncher = new WeakReference<Launcher>(launcher);
120 }
121
122 void stop() {
123 mStopped = true;
124 }
125
126 boolean isRunning() {
127 return mRunning;
128 }
129
130 public void run() {
131 mRunning = true;
132
133 Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
134 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
135
136 final Launcher launcher = mLauncher.get();
137 final PackageManager manager = launcher.getPackageManager();
138 final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
139
140 if (apps != null && !mStopped) {
141 final int count = apps.size();
142 final ApplicationsAdapter applicationList = mApplicationsAdapter;
143
144 ChangeNotifier action = new ChangeNotifier(applicationList);
145
146 for (int i = 0; i < count && !mStopped; i++) {
147 ApplicationInfo application = new ApplicationInfo();
148 ResolveInfo info = apps.get(i);
149
150 application.title = info.loadLabel(manager);
151 if (application.title == null) {
152 application.title = info.activityInfo.name;
153 }
154 application.setActivity(new ComponentName(
155 info.activityInfo.applicationInfo.packageName,
156 info.activityInfo.name),
157 Intent.FLAG_ACTIVITY_NEW_TASK |
158 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
159 application.icon = info.activityInfo.loadIcon(manager);
160 application.container = ItemInfo.NO_ID;
161
162 action.add(application);
163 }
164
165 action.sort(new Comparator<ApplicationInfo>() {
166 public final int compare(ApplicationInfo a, ApplicationInfo b) {
167 return sCollator.compare(a.title, b.title);
168 }
169 });
170
171 if (!mStopped) {
172 launcher.runOnUiThread(action);
173 }
174 }
175
176 if (!mStopped) {
177 mApplicationsLoaded = true;
178 }
179 mRunning = false;
180 }
181 }
182
183 private static class ChangeNotifier implements Runnable {
184 private final ApplicationsAdapter mApplicationList;
185 private ArrayList<ApplicationInfo> mBuffer;
186
187 ChangeNotifier(ApplicationsAdapter applicationList) {
188 mApplicationList = applicationList;
189 mBuffer = new ArrayList<ApplicationInfo>(UI_NOTIFICATION_RATE);
190 }
191
192 public void run() {
193 final ArrayList<ApplicationInfo> buffer = mBuffer;
194 final ApplicationsAdapter applicationList = mApplicationList;
195 final int count = buffer.size();
196
197 applicationList.clear();
198 for (int i = 0; i < count; i++) {
199 applicationList.setNotifyOnChange(false);
200 applicationList.add(buffer.get(i));
201 }
202
203 applicationList.notifyDataSetChanged();
204 buffer.clear();
205 }
206
207 void add(ApplicationInfo application) {
208 mBuffer.add(application);
209 }
210
211 void sort(Comparator<ApplicationInfo> comparator) {
212 Collections.sort(mBuffer, comparator);
213 }
214 }
215
216 boolean isDesktopLoaded() {
217 return mDesktopItems != null && mDesktopItemsLoaded;
218 }
219
220 /**
221 * Loads all of the items on the desktop, in folders, or in the dock.
222 * These can be apps, shortcuts or widgets
223 */
224 void loadUserItems(boolean isLaunching, Launcher launcher) {
225 if (isLaunching && mDesktopItems != null && mDesktopItemsLoaded) {
226 // We have already loaded our data from the DB
227 launcher.onDesktopItemsLoaded();
228 return;
229 }
230
231 if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
232 mDesktopItemsLoader.stop();
233 // Wait for the currently running thread to finish, this can take a little
234 // time but it should be well below the timeout limit
235 try {
236 mDesktopLoader.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
237 } catch (InterruptedException e) {
238 // Empty
239 }
240 }
241
242 mDesktopItemsLoaded = false;
243 mDesktopItemsLoader = new DesktopItemsLoader(launcher);
244 mDesktopLoader = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
245 mDesktopLoader.start();
246 }
247
248 private class DesktopItemsLoader implements Runnable {
249 private volatile boolean mStopped;
250 private volatile boolean mRunning;
251
252 private final WeakReference<Launcher> mLauncher;
253
254 DesktopItemsLoader(Launcher launcher) {
255 mLauncher = new WeakReference<Launcher>(launcher);
256 }
257
258 void stop() {
259 mStopped = true;
260 }
261
262 boolean isRunning() {
263 return mRunning;
264 }
265
266 public void run() {
267 mRunning = true;
268
269 final Launcher launcher = mLauncher.get();
270
271 mDesktopItems = new ArrayList<ItemInfo>();
272 mUserFolders = new HashMap<Long, UserFolderInfo>();
273
274 final ArrayList<ItemInfo> desktopItems = mDesktopItems;
275
276 final Cursor c = launcher.getContentResolver().query(Settings.Favorites.CONTENT_URI,
277 null, null, null, null);
278
279 try {
280 final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites.ID);
281 final int intentIndex = c.getColumnIndexOrThrow(Settings.Favorites.INTENT);
282 final int titleIndex = c.getColumnIndexOrThrow(Settings.Favorites.TITLE);
283 final int iconTypeIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_TYPE);
284 final int iconIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON);
285 final int iconPackageIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_PACKAGE);
286 final int iconResourceIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_RESOURCE);
287 final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER);
288 final int itemTypeIndex = c.getColumnIndexOrThrow(Settings.Favorites.ITEM_TYPE);
289 final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN);
290 final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
291 final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
292
293 final PackageManager manager = launcher.getPackageManager();
294
295 ApplicationInfo info;
296 String intentDescription;
297 Widget widgetInfo = null;
298 int container;
299
300 final HashMap<Long, UserFolderInfo> userFolders = mUserFolders;
301
302 while (!mStopped && c.moveToNext()) {
303 try {
304 int itemType = c.getInt(itemTypeIndex);
305
306 switch (itemType) {
307 case Settings.Favorites.ITEM_TYPE_APPLICATION:
308 case Settings.Favorites.ITEM_TYPE_SHORTCUT:
309 intentDescription = c.getString(intentIndex);
310 Intent intent;
311 try {
312 intent = Intent.getIntent(intentDescription);
313 } catch (java.net.URISyntaxException e) {
314 continue;
315 }
316
317 if (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION) {
318 info = getApplicationInfo(manager, intent);
319 } else {
320 info = getApplicationInfoShortcut(c, launcher, iconTypeIndex,
321 iconPackageIndex, iconResourceIndex, iconIndex);
322 }
323
324 if (info == null) {
325 info = new ApplicationInfo();
326 info.icon = manager.getDefaultActivityIcon();
327 }
328
329 if (info != null) {
330 info.title = c.getString(titleIndex);
331 info.intent = intent;
332
333 info.id = c.getLong(idIndex);
334 container = c.getInt(containerIndex);
335 info.container = container;
336 info.screen = c.getInt(screenIndex);
337 info.cellX = c.getInt(cellXIndex);
338 info.cellY = c.getInt(cellYIndex);
339
340 switch (container) {
341 case Settings.Favorites.CONTAINER_DESKTOP:
342 desktopItems.add(info);
343 break;
344 default:
345 // Item is in a user folder
346 UserFolderInfo folderInfo =
347 findOrMakeFolder(userFolders, container);
348 folderInfo.add(info);
349 break;
350 }
351 }
352 break;
353 case Settings.Favorites.ITEM_TYPE_USER_FOLDER:
354
355 long id = c.getLong(idIndex);
356 UserFolderInfo folderInfo = findOrMakeFolder(userFolders, id);
357
358 folderInfo.title = c.getString(titleIndex);
359
360 folderInfo.id = id;
361 container = c.getInt(containerIndex);
362 folderInfo.container = container;
363 folderInfo.screen = c.getInt(screenIndex);
364 folderInfo.cellX = c.getInt(cellXIndex);
365 folderInfo.cellY = c.getInt(cellYIndex);
366
367 switch (container) {
368 case Settings.Favorites.CONTAINER_DESKTOP:
369 desktopItems.add(folderInfo);
370 break;
371 default:
372
373 }
374 break;
375 case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
376 case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
377 case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
378 switch (itemType) {
379 case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
380 widgetInfo = Widget.makeClock();
381 break;
382 case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
383 widgetInfo = Widget.makeSearch();
384 break;
385 case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
386 widgetInfo = Widget.makePhotoFrame();
387 byte[] data = c.getBlob(iconIndex);
388 if (data != null) {
389 widgetInfo.photo =
390 BitmapFactory.decodeByteArray(data, 0, data.length);
391 }
392 break;
393 }
394
395 if (widgetInfo != null) {
396 container = c.getInt(containerIndex);
397 if (container != Settings.Favorites.CONTAINER_DESKTOP) {
398 Log.e(Launcher.LOG_TAG, "Widget found where container "
399 + "!= CONTAINER_DESKTOP -- ignoring!");
400 continue;
401 }
402 widgetInfo.id = c.getLong(idIndex);
403 widgetInfo.screen = c.getInt(screenIndex);
404 widgetInfo.container = container;
405 widgetInfo.cellX = c.getInt(cellXIndex);
406 widgetInfo.cellY = c.getInt(cellYIndex);
407
408 desktopItems.add(widgetInfo);
409 }
410 break;
411 }
412 } catch (Exception e) {
413 Log.w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
414 }
415 }
416 } finally {
417 c.close();
418 }
419
420 if (!mStopped) {
421 launcher.runOnUiThread(new Runnable() {
422 public void run() {
423 launcher.onDesktopItemsLoaded();
424 }
425 });
426 }
427
428 if (!mStopped) {
429 mDesktopItemsLoaded = true;
430 }
431 mRunning = false;
432 }
433 }
434
435 /**
436 * Finds the user folder defined by the specified id.
437 *
438 * @param id The id of the folder to look for.
439 *
440 * @return A UserFolderInfo if the folder exists or null otherwise.
441 */
442 UserFolderInfo findFolderById(long id) {
443 return mUserFolders.get(id);
444 }
445
446 void addUserFolder(UserFolderInfo info) {
447 mUserFolders.put(info.id, info);
448 }
449
450 /**
451 * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
452 * new one.
453 */
454 private UserFolderInfo findOrMakeFolder(HashMap<Long, UserFolderInfo> userFolders, long id) {
455 UserFolderInfo folderInfo;
456 // See if a placeholder was created for us already
457 folderInfo = userFolders.get(id);
458 if (folderInfo == null) {
459 // No placeholder -- create a new instance
460 folderInfo = new UserFolderInfo();
461 userFolders.put(id, folderInfo);
462 }
463 return folderInfo;
464 }
465
466 /**
467 * Remove the callback for the cached drawables or we leak the previous
468 * Home screen on orientation change.
469 */
470 void unbind() {
471 mApplicationsAdapter = null;
472 unbindAppDrawables(mApplications);
473 unbindDrawables(mDesktopItems);
474 }
475
476 /**
477 * Remove the callback for the cached drawables or we leak the previous
478 * Home screen on orientation change.
479 */
480 private void unbindDrawables(ArrayList<ItemInfo> desktopItems) {
481 if (desktopItems != null) {
482 final int count = desktopItems.size();
483 for (int i = 0; i < count; i++) {
484 ItemInfo item = desktopItems.get(i);
485 switch (item.itemType) {
486 case Settings.Favorites.ITEM_TYPE_APPLICATION:
487 case Settings.Favorites.ITEM_TYPE_SHORTCUT:
488 ((ApplicationInfo)item).icon.setCallback(null);
489 }
490 }
491 }
492 }
493
494 /**
495 * Remove the callback for the cached drawables or we leak the previous
496 * Home screen on orientation change.
497 */
498 private void unbindAppDrawables(ArrayList<ApplicationInfo> applications) {
499 if (applications != null) {
500 final int count = applications.size();
501 for (int i = 0; i < count; i++) {
502 applications.get(i).icon.setCallback(null);
503 }
504 }
505 }
506
507 /**
508 * @return The current list of applications
509 */
510 public ArrayList<ApplicationInfo> getApplications() {
511 return mApplications;
512 }
513
514 /**
515 * @return The current list of applications
516 */
517 public ApplicationsAdapter getApplicationsAdapter() {
518 return mApplicationsAdapter;
519 }
520
521 /**
522 * @return The current list of desktop items
523 */
524 public ArrayList<ItemInfo> getDesktopItems() {
525 return mDesktopItems;
526 }
527
528 /**
529 * Add an item to the desktop
530 * @param info
531 */
532 public void addDesktopItem(ItemInfo info) {
533 // TODO: write to DB; also check that folder has been added to folders list
534 mDesktopItems.add(info);
535 }
536
537 /**
538 * Remove an item from the desktop
539 * @param info
540 */
541 public void removeDesktopItem(ItemInfo info) {
542 // TODO: write to DB; figure out if we should remove folder from folders list
543 mDesktopItems.remove(info);
544 }
545
546 /**
547 * Make an ApplicationInfo object for an application
548 */
549 private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent) {
550 final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);
551
552 if (resolveInfo == null) {
553 return null;
554 }
555
556 final ApplicationInfo info = new ApplicationInfo();
557 final ActivityInfo activityInfo = resolveInfo.activityInfo;
558 info.icon = activityInfo.loadIcon(manager);
559 if (info.title == null || info.title.length() == 0) {
560 info.title = activityInfo.loadLabel(manager);
561 }
562 if (info.title == null) {
563 info.title = "";
564 }
565 info.itemType = Settings.Favorites.ITEM_TYPE_APPLICATION;
566 return info;
567 }
568
569 /**
570 * Make an ApplicationInfo object for a sortcut
571 */
572 private ApplicationInfo getApplicationInfoShortcut(Cursor c, Launcher launcher,
573 int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
574
575 final ApplicationInfo info = new ApplicationInfo();
576 info.itemType = Settings.Favorites.ITEM_TYPE_SHORTCUT;
577
578 int iconType = c.getInt(iconTypeIndex);
579 switch (iconType) {
580 case Settings.Favorites.ICON_TYPE_RESOURCE:
581 String packageName = c.getString(iconPackageIndex);
582 String resourceName = c.getString(iconResourceIndex);
583 PackageManager packageManager = launcher.getPackageManager();
584 try {
585 Resources resources = packageManager.getResourcesForApplication(packageName);
586 final int id = resources.getIdentifier(resourceName, null, null);
587 info.icon = resources.getDrawable(id);
588 } catch (Exception e) {
589 info.icon = packageManager.getDefaultActivityIcon();
590 }
591 info.iconResource = new Intent.ShortcutIconResource();
592 info.iconResource.packageName = packageName;
593 info.iconResource.resourceName = resourceName;
594 info.customIcon = false;
595 break;
596 case Settings.Favorites.ICON_TYPE_BITMAP:
597 byte[] data = c.getBlob(iconIndex);
598 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
599 info.icon = new BitmapDrawable(Utilities.createBitmapThumbnail(bitmap, launcher));
600 info.filtered = true;
601 info.customIcon = true;
602 break;
603 default:
604 info.icon = launcher.getPackageManager().getDefaultActivityIcon();
605 info.customIcon = false;
606 break;
607 }
608 return info;
609 }
610
611 /**
612 * Remove an item from the in-memory represention of a user folder. Does not change the DB.
613 */
614 void removeUserFolderItem(UserFolderInfo folder, ItemInfo info) {
615 //noinspection SuspiciousMethodCalls
616 folder.contents.remove(info);
617 }
618
619 /**
620 * Removes a UserFolder from the in-memory list of folders. Does not change the DB.
621 * @param userFolderInfo
622 */
623 void removeUserFolder(UserFolderInfo userFolderInfo) {
624 mUserFolders.remove(userFolderInfo.id);
625 }
626
627 /**
628 * Adds an item to the DB if it was not created previously, or move it to a new
629 * <container, screen, cellX, cellY>
630 */
631 static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,
632 int screen, int cellX, int cellY) {
633 if (item.container == ItemInfo.NO_ID) {
634 // From all apps
635 addItemToDatabase(context, item, container, screen, cellX, cellY, false);
636 } else {
637 // From somewhere else
638 moveItemInDatabase(context, item, container, screen, cellX, cellY);
639 }
640 }
641
642 /**
643 * Move an item in the DB to a new <container, screen, cellX, cellY>
644 */
645 static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
646 int cellX, int cellY) {
647 item.container = container;
648 item.screen = screen;
649 item.cellX = cellX;
650 item.cellY = cellY;
651
652 final ContentValues values = new ContentValues();
653 final ContentResolver cr = context.getContentResolver();
654
655 values.put(Settings.Favorites.CONTAINER, item.container);
656 values.put(Settings.Favorites.CELLX, item.cellX);
657 values.put(Settings.Favorites.CELLY, item.cellY);
658 values.put(Settings.Favorites.SCREEN, item.screen);
659
660 cr.update(Settings.Favorites.getContentUri(item.id, false), values, null, null);
661 }
662
663 /**
664 * Returns true if the shortcuts already exists in the database.
665 * we identify a shortcut by its title and intent.
666 */
667 static boolean shortcutExists(Context context, String title, Intent intent) {
668 final ContentResolver cr = context.getContentResolver();
669 Cursor c = cr.query(Settings.Favorites.CONTENT_URI,
670 new String[] { "title", "intent" }, "title=? and intent=?",
671 new String[] { title, intent.toURI() }, null);
672 boolean result = false;
673 try {
674 result = c.moveToFirst();
675 } finally {
676 c.close();
677 }
678 return result;
679 }
680
681 UserFolderInfo getFolderById(Context context, long id) {
682 final ContentResolver cr = context.getContentResolver();
683 Cursor c = cr.query(Settings.Favorites.CONTENT_URI, null, "_id=? and itemType=?",
684 new String[] { String.valueOf(id),
685 String.valueOf(Settings.Favorites.ITEM_TYPE_USER_FOLDER) }, null);
686
687 try {
688 if (c.moveToFirst()) {
689 final int titleIndex = c.getColumnIndexOrThrow(Settings.Favorites.TITLE);
690 final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER);
691 final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN);
692 final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
693 final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
694
695 UserFolderInfo folderInfo = findOrMakeFolder(mUserFolders, id);
696
697 folderInfo.title = c.getString(titleIndex);
698 folderInfo.id = id;
699 folderInfo.container = c.getInt(containerIndex);
700 folderInfo.screen = c.getInt(screenIndex);
701 folderInfo.cellX = c.getInt(cellXIndex);
702 folderInfo.cellY = c.getInt(cellYIndex);
703
704 return folderInfo;
705 }
706 } finally {
707 c.close();
708 }
709
710 return null;
711 }
712
713 static Widget getPhotoFrameInfo(Context context, int screen, int cellX, int cellY) {
714 final ContentResolver cr = context.getContentResolver();
715 Cursor c = cr.query(Settings.Favorites.CONTENT_URI,
716 null, "screen=? and cellX=? and cellY=? and itemType=?",
717 new String[] { String.valueOf(screen), String.valueOf(cellX), String.valueOf(cellY),
718 String.valueOf(Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) }, null);
719
720 try {
721 if (c.moveToFirst()) {
722 final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites.ID);
723 final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER);
724 final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN);
725 final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
726 final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
727
728 Widget widgetInfo = Widget.makePhotoFrame();
729 widgetInfo.id = c.getLong(idIndex);
730 widgetInfo.screen = c.getInt(screenIndex);
731 widgetInfo.container = c.getInt(containerIndex);
732 widgetInfo.cellX = c.getInt(cellXIndex);
733 widgetInfo.cellY = c.getInt(cellYIndex);
734
735 return widgetInfo;
736 }
737 } finally {
738 c.close();
739 }
740
741 return null;
742 }
743
744 /**
745 * Add an item to the database in a specified container. Sets the container, screen, cellX and
746 * cellY fields of the item. Also assigns an ID to the item.
747 */
748 static void addItemToDatabase(Context context, ItemInfo item, long container,
749 int screen, int cellX, int cellY, boolean notify) {
750 item.container = container;
751 item.screen = screen;
752 item.cellX = cellX;
753 item.cellY = cellY;
754
755 final ContentValues values = new ContentValues();
756 final ContentResolver cr = context.getContentResolver();
757
758 item.onAddToDatabase(values);
759
760 Uri result = cr.insert(notify ? Settings.Favorites.CONTENT_URI :
761 Settings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
762
763 if (result != null) {
764 item.id = Integer.parseInt(result.getPathSegments().get(1));
765 }
766 }
767
768 /**
769 * Update an item to the database in a specified container.
770 */
771 static void updateItemInDatabase(Context context, ItemInfo item) {
772 final ContentValues values = new ContentValues();
773 final ContentResolver cr = context.getContentResolver();
774
775 item.onAddToDatabase(values);
776
777 cr.update(Settings.Favorites.getContentUri(item.id, false), values, null, null);
778 }
779
780 /**
781 * Removes the specified item from the database
782 * @param context
783 * @param item
784 */
785 static void deleteItemFromDatabase(Context context, ItemInfo item) {
786 final ContentResolver cr = context.getContentResolver();
787
788 cr.delete(Settings.Favorites.getContentUri(item.id, false), null, null);
789 }
790
791
792 /**
793 * Remove the contents of the specified folder from the database
794 */
795 static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
796 final ContentResolver cr = context.getContentResolver();
797
798 cr.delete(Settings.Favorites.getContentUri(info.id, false), null, null);
799 cr.delete(Settings.Favorites.CONTENT_URI, Settings.Favorites.CONTAINER + "=" + info.id,
800 null);
801 }
802}