1e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal/*
2e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * Copyright (C) 2014 The Android Open Source Project
3e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal *
4e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * Licensed under the Apache License, Version 2.0 (the "License");
5e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * you may not use this file except in compliance with the License.
6e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * You may obtain a copy of the License at
7e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal *
8e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal *      http://www.apache.org/licenses/LICENSE-2.0
9e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal *
10e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * Unless required by applicable law or agreed to in writing, software
11e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * distributed under the License is distributed on an "AS IS" BASIS,
12e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * See the License for the specific language governing permissions and
14e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal * limitations under the License.
15e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal */
16e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
17e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalpackage com.android.launcher3.compat;
18e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
19e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.Context;
20817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschlerimport android.content.pm.ApplicationInfo;
21e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.pm.PackageInstaller;
22e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.pm.PackageInstaller.SessionCallback;
23800a4f217a5b0b7817a70a24974fc13d6b7e4591Sunny Goyalimport android.content.pm.PackageInstaller.SessionInfo;
24d90e938db0523c13f0301ea8cbb2cef4cf044efcSunny Goyalimport android.os.Handler;
257c74e4ae641e76f73d74348e293c244a157f6585Sunny Goyalimport android.os.Process;
267c74e4ae641e76f73d74348e293c244a157f6585Sunny Goyalimport android.os.UserHandle;
276d696f8d7c4ce933eaea4e8d86270ef6a1fc07c3Mario Bertschlerimport android.text.TextUtils;
28e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.util.SparseArray;
29e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
30349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyalimport com.android.launcher3.IconCache;
31e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport com.android.launcher3.LauncherAppState;
32756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyalimport com.android.launcher3.LauncherModel;
33817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschlerimport com.android.launcher3.config.FeatureFlags;
34091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
35e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
36817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschlerimport java.util.ArrayList;
37756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyalimport java.util.HashMap;
38817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschlerimport java.util.Iterator;
39817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschlerimport java.util.List;
40e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
41756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyalpublic class PackageInstallerCompatVL extends PackageInstallerCompat {
42e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
43817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    private static final boolean DEBUG = false;
44817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler
45756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal    @Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
46d90e938db0523c13f0301ea8cbb2cef4cf044efcSunny Goyal
47091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk final PackageInstaller mInstaller;
48349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal    private final IconCache mCache;
49d90e938db0523c13f0301ea8cbb2cef4cf044efcSunny Goyal    private final Handler mWorker;
50817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    private final Context mAppContext;
51817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    private final HashMap<String,Boolean> mSessionVerifiedMap = new HashMap<>();
52e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
53e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    PackageInstallerCompatVL(Context context) {
54817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        mAppContext = context.getApplicationContext();
55e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        mInstaller = context.getPackageManager().getPackageInstaller();
5687f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal        mCache = LauncherAppState.getInstance(context).getIconCache();
57756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal        mWorker = new Handler(LauncherModel.getWorkerLooper());
58d90e938db0523c13f0301ea8cbb2cef4cf044efcSunny Goyal        mInstaller.registerSessionCallback(mCallback, mWorker);
59e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    }
60e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
61e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    @Override
62756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal    public HashMap<String, Integer> updateAndGetActiveSessionCache() {
63756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal        HashMap<String, Integer> activePackages = new HashMap<>();
647c74e4ae641e76f73d74348e293c244a157f6585Sunny Goyal        UserHandle user = Process.myUserHandle();
65817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        for (SessionInfo info : getAllVerifiedSessions()) {
660de011705b132eacdd10f7bfb5cdc4bd79a147e8Hyunyoung Song            addSessionInfoToCache(info, user);
679448536b113afa6ceefce26604a1b44618d1d4f2Sunny Goyal            if (info.getAppPackageName() != null) {
68756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal                activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100));
69756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal                mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
709448536b113afa6ceefce26604a1b44618d1d4f2Sunny Goyal            }
71349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal        }
729448536b113afa6ceefce26604a1b44618d1d4f2Sunny Goyal        return activePackages;
73349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal    }
74349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal
757c74e4ae641e76f73d74348e293c244a157f6585Sunny Goyal    @Thunk void addSessionInfoToCache(SessionInfo info, UserHandle user) {
76349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal        String packageName = info.getAppPackageName();
77349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal        if (packageName != null) {
78349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal            mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(),
79349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal                    info.getAppLabel());
80349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal        }
81349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal    }
82349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal
83349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal    @Override
84e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    public void onStop() {
853d0854e4b8c0a6daaa80ac14c6bc7572a4e90916Dharmesh Mokani        mInstaller.unregisterSessionCallback(mCallback);
86e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    }
87e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
88756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal    @Thunk void sendUpdate(PackageInstallInfo info) {
89e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
90756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal        if (app != null) {
91756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            app.getModel().setPackageState(info);
92a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal        }
93e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    }
94e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
95e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    private final SessionCallback mCallback = new SessionCallback() {
96e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
97e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        @Override
98e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        public void onCreated(int sessionId) {
99817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId);
100817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS && sessionInfo != null) {
101817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                LauncherAppState app = LauncherAppState.getInstanceNoCreate();
102817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                if (app != null) {
103817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                    app.getModel().onInstallSessionCreated(
104817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                            PackageInstallInfo.fromInstallingState(sessionInfo));
105817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                }
106817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            }
107e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        }
108e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
109e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        @Override
110e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        public void onFinished(int sessionId, boolean success) {
111756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            // For a finished session, we can't get the session info. So use the
112756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            // packageName from our local cache.
113756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            String packageName = mActiveSessions.get(sessionId);
114756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            mActiveSessions.remove(sessionId);
115756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal
116756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            if (packageName != null) {
117817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                sendUpdate(PackageInstallInfo.fromState(
118817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                        success ? STATUS_INSTALLED : STATUS_FAILED,
119817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                        packageName));
120e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal            }
121e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        }
122e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
123e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        @Override
124e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        public void onProgressChanged(int sessionId, float progress) {
125817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            SessionInfo session = verify(mInstaller.getSessionInfo(sessionId));
126ec88204389ffc0d5fdbe656c683d5844b9c8b49bSunny Goyal            if (session != null && session.getAppPackageName() != null) {
127817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                sendUpdate(PackageInstallInfo.fromInstallingState(session));
128e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal            }
129e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        }
130e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
131e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        @Override
132f9847b9bd3e5286fe10667ec12dab5b4c43355faDharmesh Mokani        public void onActiveChanged(int sessionId, boolean active) { }
133e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal
134e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal        @Override
135a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal        public void onBadgingChanged(int sessionId) {
136756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal            pushSessionDisplayToLauncher(sessionId);
137a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal        }
138a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal
139817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        private SessionInfo pushSessionDisplayToLauncher(int sessionId) {
140817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            SessionInfo session = verify(mInstaller.getSessionInfo(sessionId));
141ec88204389ffc0d5fdbe656c683d5844b9c8b49bSunny Goyal            if (session != null && session.getAppPackageName() != null) {
142817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                mActiveSessions.put(sessionId, session.getAppPackageName());
1437c74e4ae641e76f73d74348e293c244a157f6585Sunny Goyal                addSessionInfoToCache(session, Process.myUserHandle());
144756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal                LauncherAppState app = LauncherAppState.getInstanceNoCreate();
145756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal                if (app != null) {
146756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal                    app.getModel().updateSessionDisplayInfo(session.getAppPackageName());
147a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal                }
148817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                return session;
149a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal            }
150817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            return null;
151a22666f68151269853e7ab6ab696ee6361bac793Sunny Goyal        }
152e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal    };
153817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler
154817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    private PackageInstaller.SessionInfo verify(PackageInstaller.SessionInfo sessionInfo) {
1556d696f8d7c4ce933eaea4e8d86270ef6a1fc07c3Mario Bertschler        if (sessionInfo == null
1566d696f8d7c4ce933eaea4e8d86270ef6a1fc07c3Mario Bertschler                || sessionInfo.getInstallerPackageName() == null
1576d696f8d7c4ce933eaea4e8d86270ef6a1fc07c3Mario Bertschler                || TextUtils.isEmpty(sessionInfo.getAppPackageName())) {
158817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            return null;
159817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        }
160bf2d46efad889fc2b123fe191845b32095748842Mario Bertschler        String pkg = sessionInfo.getInstallerPackageName();
161817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        synchronized (mSessionVerifiedMap) {
162817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            if (!mSessionVerifiedMap.containsKey(pkg)) {
163817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext);
164817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg,
165817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                        ApplicationInfo.FLAG_SYSTEM, Process.myUserHandle()) != null;
166817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
167817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            }
168817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        }
169817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        return mSessionVerifiedMap.get(pkg) ? sessionInfo : null;
170817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    }
171817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler
172817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    @Override
173817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    public List<SessionInfo> getAllVerifiedSessions() {
174817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        List<SessionInfo> list = new ArrayList<>(mInstaller.getAllSessions());
175817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        Iterator<SessionInfo> it = list.iterator();
176817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        while (it.hasNext()) {
177817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            if (verify(it.next()) == null) {
178817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler                it.remove();
179817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler            }
180817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        }
181817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler        return list;
182817afa34472dba49b1dee0489da11f410ff09fcdMario Bertschler    }
183e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyal}
184