1 /*
2  * Copyright (C) 2014 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.launcher3.compat;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.LauncherActivityInfo;
24 import android.graphics.Rect;
25 import android.os.Bundle;
26 import android.os.UserHandle;
27 import android.support.annotation.Nullable;
28 
29 import com.android.launcher3.LauncherAppState;
30 import com.android.launcher3.LauncherModel;
31 import com.android.launcher3.ShortcutInfo;
32 import com.android.launcher3.Utilities;
33 import com.android.launcher3.graphics.LauncherIcons;
34 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
35 import com.android.launcher3.util.LooperExecuter;
36 import com.android.launcher3.util.PackageUserKey;
37 
38 import java.util.List;
39 
40 public abstract class LauncherAppsCompat {
41 
42     public interface OnAppsChangedCallbackCompat {
onPackageRemoved(String packageName, UserHandle user)43         void onPackageRemoved(String packageName, UserHandle user);
onPackageAdded(String packageName, UserHandle user)44         void onPackageAdded(String packageName, UserHandle user);
onPackageChanged(String packageName, UserHandle user)45         void onPackageChanged(String packageName, UserHandle user);
onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing)46         void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing);
onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing)47         void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
onPackagesSuspended(String[] packageNames, UserHandle user)48         void onPackagesSuspended(String[] packageNames, UserHandle user);
onPackagesUnsuspended(String[] packageNames, UserHandle user)49         void onPackagesUnsuspended(String[] packageNames, UserHandle user);
onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts, UserHandle user)50         void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
51                 UserHandle user);
52     }
53 
LauncherAppsCompat()54     protected LauncherAppsCompat() {
55     }
56 
57     private static LauncherAppsCompat sInstance;
58     private static Object sInstanceLock = new Object();
59 
getInstance(Context context)60     public static LauncherAppsCompat getInstance(Context context) {
61         synchronized (sInstanceLock) {
62             if (sInstance == null) {
63                 if (Utilities.isAtLeastO()) {
64                     sInstance = new LauncherAppsCompatVO(context.getApplicationContext());
65                 } else {
66                     sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
67                 }
68             }
69             return sInstance;
70         }
71     }
72 
getActivityList(String packageName, UserHandle user)73     public abstract List<LauncherActivityInfo> getActivityList(String packageName,
74             UserHandle user);
resolveActivity(Intent intent, UserHandle user)75     public abstract LauncherActivityInfo resolveActivity(Intent intent,
76             UserHandle user);
startActivityForProfile(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts)77     public abstract void startActivityForProfile(ComponentName component, UserHandle user,
78             Rect sourceBounds, Bundle opts);
getApplicationInfo( String packageName, int flags, UserHandle user)79     public abstract ApplicationInfo getApplicationInfo(
80             String packageName, int flags, UserHandle user);
showAppDetailsForProfile(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts)81     public abstract void showAppDetailsForProfile(ComponentName component, UserHandle user,
82             Rect sourceBounds, Bundle opts);
addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener)83     public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener)84     public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
isPackageEnabledForProfile(String packageName, UserHandle user)85     public abstract boolean isPackageEnabledForProfile(String packageName, UserHandle user);
isActivityEnabledForProfile(ComponentName component, UserHandle user)86     public abstract boolean isActivityEnabledForProfile(ComponentName component,
87             UserHandle user);
getCustomShortcutActivityList( @ullable PackageUserKey packageUser)88     public abstract List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
89             @Nullable PackageUserKey packageUser);
90 
91     /**
92      * request.accept() will initiate the following flow:
93      *      -> go-to-system-process for actual processing (a)
94      *      -> callback-to-launcher on UI thread (b)
95      *      -> post callback on the worker thread (c)
96      *      -> Update model and unpin (in system) any shortcut not in out model. (d)
97      *
98      * Note that (b) will take at-least one frame as it involves posting callback from binder
99      * thread to UI thread.
100      * If (d) happens before we add this shortcut to our model, we will end up unpinning
101      * the shortcut in the system.
102      * Here its the caller's responsibility to add the newly created ShortcutInfo immediately
103      * to the model (which may involves a single post-to-worker-thread). That will guarantee
104      * that (d) happens after model is updated.
105      */
106     @Nullable
createShortcutInfoFromPinItemRequest( Context context, final PinItemRequestCompat request, final long acceptDelay)107     public static ShortcutInfo createShortcutInfoFromPinItemRequest(
108             Context context, final PinItemRequestCompat request, final long acceptDelay) {
109         if (request != null &&
110                 request.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT &&
111                 request.isValid()) {
112 
113             if (acceptDelay <= 0) {
114                 if (!request.accept()) {
115                     return null;
116                 }
117             } else {
118                 // Block the worker thread until the accept() is called.
119                 new LooperExecuter(LauncherModel.getWorkerLooper()).execute(new Runnable() {
120                     @Override
121                     public void run() {
122                         try {
123                             Thread.sleep(acceptDelay);
124                         } catch (InterruptedException e) {
125                             // Ignore
126                         }
127                         if (request.isValid()) {
128                             request.accept();
129                         }
130                     }
131                 });
132             }
133 
134             ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo());
135             ShortcutInfo info = new ShortcutInfo(compat, context);
136             // Apply the unbadged icon and fetch the actual icon asynchronously.
137             info.iconBitmap = LauncherIcons
138                     .createShortcutIcon(compat, context, false /* badged */);
139             LauncherAppState.getInstance(context).getModel()
140                     .updateAndBindShortcutInfo(info, compat);
141             return info;
142         } else {
143             return null;
144         }
145     }
146 
showAppDetailsForProfile(ComponentName component, UserHandle user)147     public void showAppDetailsForProfile(ComponentName component, UserHandle user) {
148         showAppDetailsForProfile(component, user, null, null);
149     }
150 }
151