LauncherAppsCompatVL.java revision ed13187a745866483139e2878037e1f8427ce567
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.graphics.Rect;
23import android.os.Build;
24import android.os.Bundle;
25import android.os.UserHandle;
26
27import java.lang.reflect.InvocationHandler;
28import java.util.ArrayList;
29import java.util.Collections;
30import java.util.HashMap;
31import java.util.List;
32import java.util.Map;
33
34import java.lang.reflect.Proxy;
35import java.lang.reflect.Method;
36
37public class LauncherAppsCompatVL extends LauncherAppsCompat {
38
39    private Object mLauncherApps;
40    private Class mLauncherAppsClass;
41    private Class mListenerClass;
42    private Method mGetActivityList;
43    private Method mResolveActivity;
44    private Method mStartActivityForProfile;
45    private Method mAddOnAppsChangedListener;
46    private Method mRemoveOnAppsChangedListener;
47    private Method mIsPackageEnabledForProfile;
48    private Method mIsActivityEnabledForProfile;
49
50    private Map<OnAppsChangedListenerCompat, Object> mListeners
51            = new HashMap<OnAppsChangedListenerCompat, Object>();
52
53    static LauncherAppsCompatVL build(Context context, Object launcherApps) {
54        LauncherAppsCompatVL compat = new LauncherAppsCompatVL(context, launcherApps);
55
56        compat.mListenerClass = ReflectUtils.getClassForName(
57                "android.content.pm.LauncherApps$OnAppsChangedListener");
58        compat.mLauncherAppsClass = ReflectUtils.getClassForName("android.content.pm.LauncherApps");
59
60        compat.mGetActivityList = ReflectUtils.getMethod(compat.mLauncherAppsClass,
61                "getActivityList",
62                String.class, UserHandle.class);
63        compat.mResolveActivity = ReflectUtils.getMethod(compat.mLauncherAppsClass,
64                "resolveActivity",
65                Intent.class, UserHandle.class);
66        compat.mStartActivityForProfile = ReflectUtils.getMethod(compat.mLauncherAppsClass,
67                "startActivityForProfile",
68                ComponentName.class, Rect.class, Bundle.class, UserHandle.class);
69        compat.mAddOnAppsChangedListener = ReflectUtils.getMethod(compat.mLauncherAppsClass,
70                "addOnAppsChangedListener", compat.mListenerClass);
71        compat.mRemoveOnAppsChangedListener = ReflectUtils.getMethod(compat.mLauncherAppsClass,
72                "removeOnAppsChangedListener", compat.mListenerClass);
73        compat.mIsPackageEnabledForProfile = ReflectUtils.getMethod(compat.mLauncherAppsClass,
74                "isPackageEnabledForProfile", String.class, UserHandle.class);
75        compat.mIsActivityEnabledForProfile = ReflectUtils.getMethod(compat.mLauncherAppsClass,
76                "isActivityEnabledForProfile", ComponentName.class, UserHandle.class);
77
78        if (compat.mListenerClass != null
79                && compat.mLauncherAppsClass != null
80                && compat.mGetActivityList != null
81                && compat.mResolveActivity != null
82                && compat.mStartActivityForProfile != null
83                && compat.mAddOnAppsChangedListener != null
84                && compat.mRemoveOnAppsChangedListener != null
85                && compat.mIsPackageEnabledForProfile != null
86                && compat.mIsActivityEnabledForProfile != null) {
87            return compat;
88        }
89        return null;
90    }
91
92    private LauncherAppsCompatVL(Context context, Object launcherApps) {
93        super();
94        mLauncherApps = launcherApps;
95    }
96
97    public List<LauncherActivityInfoCompat> getActivityList(String packageName,
98            UserHandleCompat user) {
99        List<Object> list = (List<Object>) ReflectUtils.invokeMethod(mLauncherApps,
100                mGetActivityList, packageName, user.getUser());
101        if (list.size() == 0) {
102            return Collections.EMPTY_LIST;
103        }
104        ArrayList<LauncherActivityInfoCompat> compatList =
105                new ArrayList<LauncherActivityInfoCompat>(list.size());
106        for (Object info : list) {
107            compatList.add(new LauncherActivityInfoCompatVL(info));
108        }
109        return compatList;
110    }
111
112    public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) {
113        return new LauncherActivityInfoCompatVL(ReflectUtils.invokeMethod(mLauncherApps,
114                        mResolveActivity, intent, user.getUser()));
115    }
116
117    public void startActivityForProfile(ComponentName component, Rect sourceBounds,
118            Bundle opts, UserHandleCompat user) {
119        ReflectUtils.invokeMethod(mLauncherApps, mStartActivityForProfile,
120                component, sourceBounds, opts, user.getUser());
121    }
122
123    public void addOnAppsChangedListener(LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
124        Object wrappedListener = Proxy.newProxyInstance(mListenerClass.getClassLoader(),
125                new Class[]{mListenerClass}, new WrappedListener(listener));
126        synchronized (mListeners) {
127            mListeners.put(listener, wrappedListener);
128        }
129        ReflectUtils.invokeMethod(mLauncherApps, mAddOnAppsChangedListener, wrappedListener);
130    }
131
132    public void removeOnAppsChangedListener(
133            LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
134        Object wrappedListener = null;
135        synchronized (mListeners) {
136            wrappedListener = mListeners.remove(listener);
137        }
138        if (wrappedListener != null) {
139            ReflectUtils.invokeMethod(mLauncherApps, mRemoveOnAppsChangedListener, wrappedListener);
140        }
141    }
142
143    public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
144        return (Boolean) ReflectUtils.invokeMethod(mLauncherApps, mIsPackageEnabledForProfile,
145                packageName, user.getUser());
146    }
147
148    public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
149        return (Boolean) ReflectUtils.invokeMethod(mLauncherApps, mIsActivityEnabledForProfile,
150                component, user.getUser());
151    }
152
153    private static class WrappedListener implements InvocationHandler {
154        private LauncherAppsCompat.OnAppsChangedListenerCompat mListener;
155
156        public WrappedListener(LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
157            mListener = listener;
158        }
159
160        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
161            try {
162                String methodName = m.getName();
163                if ("onPackageRemoved".equals(methodName)) {
164                    onPackageRemoved((UserHandle) args[0], (String) args[1]);
165                } else if ("onPackageAdded".equals(methodName)) {
166                    onPackageAdded((UserHandle) args[0], (String) args[1]);
167                } else if ("onPackageChanged".equals(methodName)) {
168                    onPackageChanged((UserHandle) args[0], (String) args[1]);
169                } else if ("onPackagesAvailable".equals(methodName)) {
170                    onPackagesAvailable((UserHandle) args[0], (String []) args[1],
171                            (Boolean) args[2]);
172                } else if ("onPackagesUnavailable".equals(methodName)) {
173                    onPackagesUnavailable((UserHandle) args[0], (String []) args[1],
174                            (Boolean) args[2]);
175                }
176            } finally {
177                return null;
178            }
179        }
180
181        public void onPackageRemoved(UserHandle user, String packageName) {
182            mListener.onPackageRemoved(UserHandleCompat.fromUser(user), packageName);
183        }
184
185        public void onPackageAdded(UserHandle user, String packageName) {
186            mListener.onPackageAdded(UserHandleCompat.fromUser(user), packageName);
187        }
188
189        public void onPackageChanged(UserHandle user, String packageName) {
190            mListener.onPackageChanged(UserHandleCompat.fromUser(user), packageName);
191        }
192
193        public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing) {
194            mListener.onPackagesAvailable(UserHandleCompat.fromUser(user), packageNames, replacing);
195        }
196
197        public void onPackagesUnavailable(UserHandle user, String[] packageNames,
198                boolean replacing) {
199            mListener.onPackagesUnavailable(UserHandleCompat.fromUser(user), packageNames,
200                    replacing);
201        }
202    }
203}
204
205