LauncherAppsCompat.java revision a2d1540c0e6051e670cabdb48976ee6da53f2c2f
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
17package com.android.launcher3.compat;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.pm.ApplicationInfo;
23import android.content.pm.LauncherActivityInfo;
24import android.graphics.Rect;
25import android.os.Bundle;
26import android.os.UserHandle;
27import android.support.annotation.Nullable;
28
29import com.android.launcher3.LauncherAppState;
30import com.android.launcher3.LauncherModel;
31import com.android.launcher3.ShortcutInfo;
32import com.android.launcher3.Utilities;
33import com.android.launcher3.graphics.LauncherIcons;
34import com.android.launcher3.shortcuts.ShortcutInfoCompat;
35import com.android.launcher3.util.LooperExecutor;
36import com.android.launcher3.util.PackageUserKey;
37
38import java.util.List;
39
40public abstract class LauncherAppsCompat {
41
42    public interface OnAppsChangedCallbackCompat {
43        void onPackageRemoved(String packageName, UserHandle user);
44        void onPackageAdded(String packageName, UserHandle user);
45        void onPackageChanged(String packageName, UserHandle user);
46        void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing);
47        void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
48        void onPackagesSuspended(String[] packageNames, UserHandle user);
49        void onPackagesUnsuspended(String[] packageNames, UserHandle user);
50        void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
51                UserHandle user);
52    }
53
54    protected LauncherAppsCompat() {
55    }
56
57    private static LauncherAppsCompat sInstance;
58    private static Object sInstanceLock = new Object();
59
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
73    public abstract List<LauncherActivityInfo> getActivityList(String packageName,
74            UserHandle user);
75    public abstract LauncherActivityInfo resolveActivity(Intent intent,
76            UserHandle user);
77    public abstract void startActivityForProfile(ComponentName component, UserHandle user,
78            Rect sourceBounds, Bundle opts);
79    public abstract ApplicationInfo getApplicationInfo(
80            String packageName, int flags, UserHandle user);
81    public abstract void showAppDetailsForProfile(ComponentName component, UserHandle user,
82            Rect sourceBounds, Bundle opts);
83    public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
84    public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
85    public abstract boolean isPackageEnabledForProfile(String packageName, UserHandle user);
86    public abstract boolean isActivityEnabledForProfile(ComponentName component,
87            UserHandle user);
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
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 LooperExecutor(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
147    public void showAppDetailsForProfile(ComponentName component, UserHandle user) {
148        showAppDetailsForProfile(component, user, null, null);
149    }
150}
151