blob: fd3f1512d4725177841f3d02b521da835e40609b [file] [log] [blame]
Jon Miranda16ea1b12017-12-12 14:52:48 -08001/*
2 * Copyright (C) 2017 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 */
16package com.android.wallpaper.model;
17
18import android.app.Activity;
19import android.app.WallpaperManager;
20import android.content.Context;
21import android.content.Intent;
Santiago Etchebehere28b242a2018-04-09 16:33:10 -070022import android.content.pm.ApplicationInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080023import android.content.pm.PackageManager;
24import android.content.pm.ResolveInfo;
25import android.content.res.Resources;
26import android.net.Uri;
27import android.os.Parcel;
28import android.service.wallpaper.WallpaperService;
29import android.support.annotation.Nullable;
30import android.util.Log;
31
32import com.android.wallpaper.R;
33import com.android.wallpaper.asset.Asset;
34import com.android.wallpaper.asset.LiveWallpaperThumbAsset;
35import com.android.wallpaper.compat.BuildCompat;
36import com.android.wallpaper.util.ActivityUtils;
37
38import org.xmlpull.v1.XmlPullParserException;
39
40import java.io.IOException;
41import java.text.Collator;
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.Collections;
45import java.util.Comparator;
46import java.util.Iterator;
47import java.util.List;
48
49/**
50 * Represents a live wallpaper from the system.
51 */
52public class LiveWallpaperInfo extends WallpaperInfo {
53 public static final Creator<LiveWallpaperInfo> CREATOR =
54 new Creator<LiveWallpaperInfo>() {
55 @Override
56 public LiveWallpaperInfo createFromParcel(Parcel in) {
57 return new LiveWallpaperInfo(in);
58 }
59
60 @Override
61 public LiveWallpaperInfo[] newArray(int size) {
62 return new LiveWallpaperInfo[size];
63 }
64 };
65 private static final String TAG = "LiveWallpaperInfo";
66 private android.app.WallpaperInfo mInfo;
67 private LiveWallpaperThumbAsset mThumbAsset;
Santiago Etchebehere98a39c12018-05-11 15:06:45 -070068 private boolean mVisibleTitle;
Jon Miranda16ea1b12017-12-12 14:52:48 -080069
70 /**
71 * Constructs a LiveWallpaperInfo wrapping the given system WallpaperInfo object, representing
72 * a particular live wallpaper.
73 *
74 * @param info
75 */
76 public LiveWallpaperInfo(android.app.WallpaperInfo info) {
Santiago Etchebehere98a39c12018-05-11 15:06:45 -070077 this(info, true);
78 }
79
80 /**
81 * Constructs a LiveWallpaperInfo wrapping the given system WallpaperInfo object, representing
82 * a particular live wallpaper.
83 */
84 public LiveWallpaperInfo(android.app.WallpaperInfo info, boolean visibleTitle) {
Jon Miranda16ea1b12017-12-12 14:52:48 -080085 mInfo = info;
Santiago Etchebehere98a39c12018-05-11 15:06:45 -070086 mVisibleTitle = visibleTitle;
Jon Miranda16ea1b12017-12-12 14:52:48 -080087 }
88
89 private LiveWallpaperInfo(Parcel in) {
90 mInfo = in.readParcelable(android.app.WallpaperInfo.class.getClassLoader());
Santiago Etchebehere98a39c12018-05-11 15:06:45 -070091 mVisibleTitle = in.readInt() == 1;
Jon Miranda16ea1b12017-12-12 14:52:48 -080092 }
93
94 /**
95 * Returns all live wallpapers found on the device, excluding those residing in APKs described by
96 * the package names in excludedPackageNames.
97 */
98 public static List<WallpaperInfo> getAll(Context context,
99 @Nullable List<String> excludedPackageNames) {
100 List<ResolveInfo> resolveInfos = getAllOnDevice(context);
101 List<WallpaperInfo> wallpaperInfos = new ArrayList<>();
102
103 for (int i = 0; i < resolveInfos.size(); i++) {
104 ResolveInfo resolveInfo = resolveInfos.get(i);
105 android.app.WallpaperInfo wallpaperInfo;
106 try {
107 wallpaperInfo = new android.app.WallpaperInfo(context, resolveInfo);
108 } catch (XmlPullParserException e) {
109 Log.w(TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
110 continue;
111 } catch (IOException e) {
112 Log.w(TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
113 continue;
114 }
115
116 if (excludedPackageNames != null && excludedPackageNames.contains(
117 wallpaperInfo.getPackageName())) {
118 continue;
119 }
120
121 wallpaperInfos.add(new LiveWallpaperInfo(wallpaperInfo));
122 }
123
124 return wallpaperInfos;
125 }
126
127 /**
128 * Returns the live wallpapers having the given service names, found within the APK with the
129 * given package name.
130 */
131 public static List<WallpaperInfo> getFromSpecifiedPackage(
Santiago Etchebehere98a39c12018-05-11 15:06:45 -0700132 Context context, String packageName, @Nullable List<String> serviceNames,
133 boolean shouldShowTitle) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800134 List<ResolveInfo> resolveInfos;
135 if (serviceNames != null) {
136 resolveInfos = getAllContainingServiceNames(context, serviceNames);
137 } else {
138 resolveInfos = getAllOnDevice(context);
139 }
140 List<WallpaperInfo> wallpaperInfos = new ArrayList<>();
141
142 for (int i = 0; i < resolveInfos.size(); i++) {
143 ResolveInfo resolveInfo = resolveInfos.get(i);
144 if (resolveInfo == null) {
145 Log.e(TAG, "Found a null resolve info");
146 continue;
147 }
148
149 android.app.WallpaperInfo wallpaperInfo;
150 try {
151 wallpaperInfo = new android.app.WallpaperInfo(context, resolveInfo);
152 } catch (XmlPullParserException e) {
153 Log.w(TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
154 continue;
155 } catch (IOException e) {
156 Log.w(TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
157 continue;
158 }
159
160 if (!packageName.equals(wallpaperInfo.getPackageName())) {
161 continue;
162 }
163
Santiago Etchebehere98a39c12018-05-11 15:06:45 -0700164 wallpaperInfos.add(new LiveWallpaperInfo(wallpaperInfo, shouldShowTitle));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800165 }
166
167 return wallpaperInfos;
168 }
169
170 /**
171 * Returns ResolveInfo objects for all live wallpaper services with the specified fully qualified
172 * service names, keeping order intact.
173 */
174 private static List<ResolveInfo> getAllContainingServiceNames(Context context,
175 List<String> serviceNames) {
176 final PackageManager pm = context.getPackageManager();
177
178 List<ResolveInfo> allResolveInfos = pm.queryIntentServices(
179 new Intent(WallpaperService.SERVICE_INTERFACE),
180 PackageManager.GET_META_DATA);
181
182 // Filter ALL live wallpapers for only those in the list of specified service names.
183 // Prefer this approach so we can make only one call to PackageManager (expensive!) rather than
184 // one call per live wallpaper.
185 ResolveInfo[] specifiedResolveInfos = new ResolveInfo[serviceNames.size()];
186 for (ResolveInfo resolveInfo : allResolveInfos) {
187 int index = serviceNames.indexOf(resolveInfo.serviceInfo.name);
188 if (index != -1) {
189 specifiedResolveInfos[index] = resolveInfo;
190 }
191 }
192
193 return Arrays.asList(specifiedResolveInfos);
194 }
195
196 /**
Santiago Etchebehere28b242a2018-04-09 16:33:10 -0700197 * Returns ResolveInfo objects for all live wallpaper services installed on the device. System
198 * wallpapers are listed first, unsorted, with other installed wallpapers following sorted
Jon Miranda16ea1b12017-12-12 14:52:48 -0800199 * in alphabetical order.
200 */
201 private static List<ResolveInfo> getAllOnDevice(Context context) {
202 final PackageManager pm = context.getPackageManager();
203 final String packageName = context.getPackageName();
204
205 List<ResolveInfo> resolveInfos = pm.queryIntentServices(
206 new Intent(WallpaperService.SERVICE_INTERFACE),
207 PackageManager.GET_META_DATA);
208
Santiago Etchebehere28b242a2018-04-09 16:33:10 -0700209 List<ResolveInfo> wallpaperInfos = new ArrayList<>();
210
211 // Remove the "Rotating Image Wallpaper" live wallpaper, which is owned by this package,
212 // and separate system wallpapers to sort only non-system ones.
213 Iterator<ResolveInfo> iter = resolveInfos.iterator();
214 while (iter.hasNext()) {
215 ResolveInfo resolveInfo = iter.next();
216 if (packageName.equals(resolveInfo.serviceInfo.packageName)) {
217 iter.remove();
218 } else if (isSystemApp(resolveInfo.serviceInfo.applicationInfo)) {
219 wallpaperInfos.add(resolveInfo);
220 iter.remove();
221 }
222 }
223
224 if (resolveInfos.isEmpty()) {
225 return wallpaperInfos;
226 }
227
228 // Sort non-system wallpapers alphabetically and append them to system ones
Jon Miranda16ea1b12017-12-12 14:52:48 -0800229 Collections.sort(resolveInfos, new Comparator<ResolveInfo>() {
230 final Collator mCollator = Collator.getInstance();
231
232 @Override
233 public int compare(ResolveInfo info1, ResolveInfo info2) {
234 return mCollator.compare(info1.loadLabel(pm), info2.loadLabel(pm));
235 }
236 });
Santiago Etchebehere28b242a2018-04-09 16:33:10 -0700237 wallpaperInfos.addAll(resolveInfos);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800238
Santiago Etchebehere28b242a2018-04-09 16:33:10 -0700239 return wallpaperInfos;
240 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800241
Santiago Etchebehere28b242a2018-04-09 16:33:10 -0700242 private static boolean isSystemApp(ApplicationInfo appInfo) {
243 return (appInfo.flags & (ApplicationInfo.FLAG_SYSTEM
244 | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800245 }
246
247 @Override
248 public String getTitle(Context context) {
Santiago Etchebehere98a39c12018-05-11 15:06:45 -0700249 if (mVisibleTitle) {
250 CharSequence labelCharSeq = mInfo.loadLabel(context.getPackageManager());
251 return labelCharSeq == null ? null : labelCharSeq.toString();
252 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800253 return null;
254 }
255
256 @Override
257 public List<String> getAttributions(Context context) {
258 List<String> attributions = new ArrayList<>();
Santiago Etchebehere71c343f2018-04-06 14:03:07 -0700259 CharSequence labelCharSeq = mInfo.loadLabel(context.getPackageManager());
260 attributions.add(labelCharSeq == null ? null : labelCharSeq.toString());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800261
262 try {
263 CharSequence authorCharSeq = mInfo.loadAuthor(context.getPackageManager());
264 if (authorCharSeq != null) {
265 String author = authorCharSeq.toString();
266 attributions.add(author);
267 }
268 } catch (Resources.NotFoundException e) {
269 // No author specified, so no other attribution to add.
270 }
271
272 return attributions;
273 }
274
275 @Override
276 public String getActionUrl(Context context) {
277 if (BuildCompat.isAtLeastNMR1()) {
278 try {
279 Uri wallpaperContextUri = mInfo.loadContextUri(context.getPackageManager());
280 if (wallpaperContextUri != null) {
281 return wallpaperContextUri.toString();
282 }
283 } catch (Resources.NotFoundException e) {
284 return null;
285 }
286 }
287
288 return null;
289 }
290
291 @Override
292 public Asset getAsset(Context context) {
293 return null;
294 }
295
296 @Override
297 public Asset getThumbAsset(Context context) {
298 if (mThumbAsset == null) {
299 mThumbAsset = new LiveWallpaperThumbAsset(context, mInfo);
300 }
301 return mThumbAsset;
302 }
303
304 @Override
305 public void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory,
306 int requestCode) {
307 Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
308 preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, mInfo.getComponent());
309 ActivityUtils.startActivityForResultSafely(srcActivity, preview, requestCode);
310 }
311
312 @Override
313 public void writeToParcel(Parcel parcel, int i) {
314 parcel.writeParcelable(mInfo, 0 /* flags */);
Santiago Etchebehere98a39c12018-05-11 15:06:45 -0700315 parcel.writeInt(mVisibleTitle ? 1 : 0);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800316 }
317
318 @Override
319 public android.app.WallpaperInfo getWallpaperComponent() {
320 return mInfo;
321 }
322
323 @Override
324 public String getCollectionId(Context context) {
325 return context.getString(R.string.live_wallpaper_collection_id);
326 }
327}