LauncherAppsCompatVL.java revision 792dd77e8c6fed786ef95da0cd9f5c342c9f1f6b
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        Object activity = ReflectUtils.invokeMethod(mLauncherApps, mResolveActivity,
114                        intent, user.getUser());
115        if (activity != null) {
116            return new LauncherActivityInfoCompatVL(activity);
117        } else {
118            return null;
119        }
120    }
121
122    public void startActivityForProfile(ComponentName component, Rect sourceBounds,
123            Bundle opts, UserHandleCompat user) {
124        ReflectUtils.invokeMethod(mLauncherApps, mStartActivityForProfile,
125                component, sourceBounds, opts, user.getUser());
126    }
127
128    public void addOnAppsChangedListener(LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
129        Object wrappedListener = Proxy.newProxyInstance(mListenerClass.getClassLoader(),
130                new Class[]{mListenerClass}, new WrappedListener(listener));
131        synchronized (mListeners) {
132            mListeners.put(listener, wrappedListener);
133        }
134        ReflectUtils.invokeMethod(mLauncherApps, mAddOnAppsChangedListener, wrappedListener);
135    }
136
137    public void removeOnAppsChangedListener(
138            LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
139        Object wrappedListener = null;
140        synchronized (mListeners) {
141            wrappedListener = mListeners.remove(listener);
142        }
143        if (wrappedListener != null) {
144            ReflectUtils.invokeMethod(mLauncherApps, mRemoveOnAppsChangedListener, wrappedListener);
145        }
146    }
147
148    public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
149        return (Boolean) ReflectUtils.invokeMethod(mLauncherApps, mIsPackageEnabledForProfile,
150                packageName, user.getUser());
151    }
152
153    public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
154        return (Boolean) ReflectUtils.invokeMethod(mLauncherApps, mIsActivityEnabledForProfile,
155                component, user.getUser());
156    }
157
158    private static class WrappedListener implements InvocationHandler {
159        private LauncherAppsCompat.OnAppsChangedListenerCompat mListener;
160
161        public WrappedListener(LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
162            mListener = listener;
163        }
164
165        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
166            try {
167                String methodName = m.getName();
168                if ("onPackageRemoved".equals(methodName)) {
169                    onPackageRemoved((UserHandle) args[0], (String) args[1]);
170                } else if ("onPackageAdded".equals(methodName)) {
171                    onPackageAdded((UserHandle) args[0], (String) args[1]);
172                } else if ("onPackageChanged".equals(methodName)) {
173                    onPackageChanged((UserHandle) args[0], (String) args[1]);
174                } else if ("onPackagesAvailable".equals(methodName)) {
175                    onPackagesAvailable((UserHandle) args[0], (String []) args[1],
176                            (Boolean) args[2]);
177                } else if ("onPackagesUnavailable".equals(methodName)) {
178                    onPackagesUnavailable((UserHandle) args[0], (String []) args[1],
179                            (Boolean) args[2]);
180                }
181            } finally {
182                return null;
183            }
184        }
185
186        public void onPackageRemoved(UserHandle user, String packageName) {
187            mListener.onPackageRemoved(UserHandleCompat.fromUser(user), packageName);
188        }
189
190        public void onPackageAdded(UserHandle user, String packageName) {
191            mListener.onPackageAdded(UserHandleCompat.fromUser(user), packageName);
192        }
193
194        public void onPackageChanged(UserHandle user, String packageName) {
195            mListener.onPackageChanged(UserHandleCompat.fromUser(user), packageName);
196        }
197
198        public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing) {
199            mListener.onPackagesAvailable(UserHandleCompat.fromUser(user), packageNames, replacing);
200        }
201
202        public void onPackagesUnavailable(UserHandle user, String[] packageNames,
203                boolean replacing) {
204            mListener.onPackagesUnavailable(UserHandleCompat.fromUser(user), packageNames,
205                    replacing);
206        }
207    }
208}
209
210