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.ContentValues;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.graphics.Bitmap;
23 import android.os.UserHandle;
24 import android.os.UserManager;
25 import android.util.Log;
26 
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 
30 /**
31  * Represents an item in the launcher.
32  */
33 class ItemInfo {
34 
35     /**
36      * Intent extra to store the profile. Format: UserHandle
37      */
38     static final String EXTRA_PROFILE = "profile";
39 
40     static final int NO_ID = -1;
41 
42     /**
43      * The id in the settings database for this item
44      */
45     long id = NO_ID;
46 
47     /**
48      * One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
49      * {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
50      * {@link LauncherSettings.Favorites#ITEM_TYPE_FOLDER}, or
51      * {@link LauncherSettings.Favorites#ITEM_TYPE_APPWIDGET}.
52      */
53     int itemType;
54 
55     /**
56      * The id of the container that holds this item. For the desktop, this will be
57      * {@link LauncherSettings.Favorites#CONTAINER_DESKTOP}. For the all applications folder it
58      * will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders
59      * it will be the id of the folder.
60      */
61     long container = NO_ID;
62 
63     /**
64      * Indicates the screen in which the shortcut appears.
65      */
66     int screen = -1;
67 
68     /**
69      * Indicates the X position of the associated cell.
70      */
71     int cellX = -1;
72 
73     /**
74      * Indicates the Y position of the associated cell.
75      */
76     int cellY = -1;
77 
78     /**
79      * Indicates the X cell span.
80      */
81     int spanX = 1;
82 
83     /**
84      * Indicates the Y cell span.
85      */
86     int spanY = 1;
87 
88     /**
89      * Indicates the minimum X cell span.
90      */
91     int minSpanX = 1;
92 
93     /**
94      * Indicates the minimum Y cell span.
95      */
96     int minSpanY = 1;
97 
98     /**
99      * Indicates that this item needs to be updated in the db
100      */
101     boolean requiresDbUpdate = false;
102 
103     /**
104      * Title of the item
105      */
106     CharSequence title;
107 
108     /**
109      * Content description for the item.
110      */
111     CharSequence contentDescription;
112 
113     /**
114      * The position of the item in a drag-and-drop operation.
115      */
116     int[] dropPos = null;
117 
118     UserHandle user;
119 
ItemInfo()120     ItemInfo() {
121         user = android.os.Process.myUserHandle();
122     }
123 
ItemInfo(ItemInfo info)124     ItemInfo(ItemInfo info) {
125         id = info.id;
126         cellX = info.cellX;
127         cellY = info.cellY;
128         spanX = info.spanX;
129         spanY = info.spanY;
130         screen = info.screen;
131         itemType = info.itemType;
132         container = info.container;
133         user = info.user;
134         contentDescription = info.contentDescription;
135         // tempdebug:
136         LauncherModel.checkItemInfo(this);
137     }
138 
139     /** Returns the package name that the intent will resolve to, or an empty string if
140      *  none exists. */
getPackageName(Intent intent)141     static String getPackageName(Intent intent) {
142         if (intent != null) {
143             String packageName = intent.getPackage();
144             if (packageName == null && intent.getComponent() != null) {
145                 packageName = intent.getComponent().getPackageName();
146             }
147             if (packageName != null) {
148                 return packageName;
149             }
150         }
151         return "";
152     }
153 
updateUser(Intent intent)154     protected void updateUser(Intent intent) {
155         if (intent != null && intent.hasExtra(EXTRA_PROFILE)) {
156             user = (UserHandle) intent.getParcelableExtra(EXTRA_PROFILE);
157         }
158     }
159 
160     /**
161      * Write the fields of this item to the DB
162      *
163      * @param context A context object to use for getting a UserManager
164      *            instance.
165      * @param values
166      */
onAddToDatabase(Context context, ContentValues values)167     void onAddToDatabase(Context context, ContentValues values) {
168         values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType);
169         values.put(LauncherSettings.Favorites.CONTAINER, container);
170         values.put(LauncherSettings.Favorites.SCREEN, screen);
171         values.put(LauncherSettings.Favorites.CELLX, cellX);
172         values.put(LauncherSettings.Favorites.CELLY, cellY);
173         values.put(LauncherSettings.Favorites.SPANX, spanX);
174         values.put(LauncherSettings.Favorites.SPANY, spanY);
175         long serialNumber = ((UserManager) context.getSystemService(Context.USER_SERVICE))
176                 .getSerialNumberForUser(user);
177         values.put(LauncherSettings.Favorites.PROFILE_ID, serialNumber);
178     }
179 
updateValuesWithCoordinates(ContentValues values, int cellX, int cellY)180     void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
181         values.put(LauncherSettings.Favorites.CELLX, cellX);
182         values.put(LauncherSettings.Favorites.CELLY, cellY);
183     }
184 
flattenBitmap(Bitmap bitmap)185     static byte[] flattenBitmap(Bitmap bitmap) {
186         // Try go guesstimate how much space the icon will take when serialized
187         // to avoid unnecessary allocations/copies during the write.
188         int size = bitmap.getWidth() * bitmap.getHeight() * 4;
189         ByteArrayOutputStream out = new ByteArrayOutputStream(size);
190         try {
191             bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
192             out.flush();
193             out.close();
194             return out.toByteArray();
195         } catch (IOException e) {
196             Log.w("Favorite", "Could not write icon");
197             return null;
198         }
199     }
200 
writeBitmap(ContentValues values, Bitmap bitmap)201     static void writeBitmap(ContentValues values, Bitmap bitmap) {
202         if (bitmap != null) {
203             byte[] data = flattenBitmap(bitmap);
204             values.put(LauncherSettings.Favorites.ICON, data);
205         }
206     }
207 
208     /**
209      * It is very important that sub-classes implement this if they contain any references
210      * to the activity (anything in the view hierarchy etc.). If not, leaks can result since
211      * ItemInfo objects persist across rotation and can hence leak by holding stale references
212      * to the old view hierarchy / activity.
213      */
unbind()214     void unbind() {
215     }
216 
217     @Override
toString()218     public String toString() {
219         return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
220             + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
221                 + " spanY=" + spanY + " dropPos=" + dropPos + " user=" + user
222                 + ")";
223     }
224 }
225