Home | History | Annotate | Download | only in compat
      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.Context;
     20 import android.content.pm.ApplicationInfo;
     21 import android.content.pm.PackageInstaller;
     22 import android.content.pm.PackageInstaller.SessionCallback;
     23 import android.content.pm.PackageInstaller.SessionInfo;
     24 import android.os.Handler;
     25 import android.os.Process;
     26 import android.os.UserHandle;
     27 import android.text.TextUtils;
     28 import android.util.SparseArray;
     29 
     30 import com.android.launcher3.IconCache;
     31 import com.android.launcher3.LauncherAppState;
     32 import com.android.launcher3.LauncherModel;
     33 import com.android.launcher3.config.FeatureFlags;
     34 import com.android.launcher3.util.Thunk;
     35 
     36 import java.util.ArrayList;
     37 import java.util.HashMap;
     38 import java.util.Iterator;
     39 import java.util.List;
     40 
     41 public class PackageInstallerCompatVL extends PackageInstallerCompat {
     42 
     43     private static final boolean DEBUG = false;
     44 
     45     @Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
     46 
     47     @Thunk final PackageInstaller mInstaller;
     48     private final IconCache mCache;
     49     private final Handler mWorker;
     50     private final Context mAppContext;
     51     private final HashMap<String,Boolean> mSessionVerifiedMap = new HashMap<>();
     52 
     53     PackageInstallerCompatVL(Context context) {
     54         mAppContext = context.getApplicationContext();
     55         mInstaller = context.getPackageManager().getPackageInstaller();
     56         mCache = LauncherAppState.getInstance(context).getIconCache();
     57         mWorker = new Handler(LauncherModel.getWorkerLooper());
     58         mInstaller.registerSessionCallback(mCallback, mWorker);
     59     }
     60 
     61     @Override
     62     public HashMap<String, SessionInfo> updateAndGetActiveSessionCache() {
     63         HashMap<String, SessionInfo> activePackages = new HashMap<>();
     64         UserHandle user = Process.myUserHandle();
     65         for (SessionInfo info : getAllVerifiedSessions()) {
     66             addSessionInfoToCache(info, user);
     67             if (info.getAppPackageName() != null) {
     68                 activePackages.put(info.getAppPackageName(), info);
     69                 mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
     70             }
     71         }
     72         return activePackages;
     73     }
     74 
     75     @Thunk void addSessionInfoToCache(SessionInfo info, UserHandle user) {
     76         String packageName = info.getAppPackageName();
     77         if (packageName != null) {
     78             mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(),
     79                     info.getAppLabel());
     80         }
     81     }
     82 
     83     @Override
     84     public void onStop() {
     85         mInstaller.unregisterSessionCallback(mCallback);
     86     }
     87 
     88     @Thunk void sendUpdate(PackageInstallInfo info) {
     89         LauncherAppState app = LauncherAppState.getInstanceNoCreate();
     90         if (app != null) {
     91             app.getModel().setPackageState(info);
     92         }
     93     }
     94 
     95     private final SessionCallback mCallback = new SessionCallback() {
     96 
     97         @Override
     98         public void onCreated(int sessionId) {
     99             SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId);
    100             if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS && sessionInfo != null) {
    101                 LauncherAppState app = LauncherAppState.getInstanceNoCreate();
    102                 if (app != null) {
    103                     app.getModel().onInstallSessionCreated(
    104                             PackageInstallInfo.fromInstallingState(sessionInfo));
    105                 }
    106             }
    107         }
    108 
    109         @Override
    110         public void onFinished(int sessionId, boolean success) {
    111             // For a finished session, we can't get the session info. So use the
    112             // packageName from our local cache.
    113             String packageName = mActiveSessions.get(sessionId);
    114             mActiveSessions.remove(sessionId);
    115 
    116             if (packageName != null) {
    117                 sendUpdate(PackageInstallInfo.fromState(
    118                         success ? STATUS_INSTALLED : STATUS_FAILED,
    119                         packageName));
    120             }
    121         }
    122 
    123         @Override
    124         public void onProgressChanged(int sessionId, float progress) {
    125             SessionInfo session = verify(mInstaller.getSessionInfo(sessionId));
    126             if (session != null && session.getAppPackageName() != null) {
    127                 sendUpdate(PackageInstallInfo.fromInstallingState(session));
    128             }
    129         }
    130 
    131         @Override
    132         public void onActiveChanged(int sessionId, boolean active) { }
    133 
    134         @Override
    135         public void onBadgingChanged(int sessionId) {
    136             pushSessionDisplayToLauncher(sessionId);
    137         }
    138 
    139         private SessionInfo pushSessionDisplayToLauncher(int sessionId) {
    140             SessionInfo session = verify(mInstaller.getSessionInfo(sessionId));
    141             if (session != null && session.getAppPackageName() != null) {
    142                 mActiveSessions.put(sessionId, session.getAppPackageName());
    143                 addSessionInfoToCache(session, Process.myUserHandle());
    144                 LauncherAppState app = LauncherAppState.getInstanceNoCreate();
    145                 if (app != null) {
    146                     app.getModel().updateSessionDisplayInfo(session.getAppPackageName());
    147                 }
    148                 return session;
    149             }
    150             return null;
    151         }
    152     };
    153 
    154     private PackageInstaller.SessionInfo verify(PackageInstaller.SessionInfo sessionInfo) {
    155         if (sessionInfo == null
    156                 || sessionInfo.getInstallerPackageName() == null
    157                 || TextUtils.isEmpty(sessionInfo.getAppPackageName())) {
    158             return null;
    159         }
    160         String pkg = sessionInfo.getInstallerPackageName();
    161         synchronized (mSessionVerifiedMap) {
    162             if (!mSessionVerifiedMap.containsKey(pkg)) {
    163                 LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext);
    164                 boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg,
    165                         ApplicationInfo.FLAG_SYSTEM, Process.myUserHandle()) != null;
    166                 mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
    167             }
    168         }
    169         return mSessionVerifiedMap.get(pkg) ? sessionInfo : null;
    170     }
    171 
    172     @Override
    173     public List<SessionInfo> getAllVerifiedSessions() {
    174         List<SessionInfo> list = new ArrayList<>(mInstaller.getAllSessions());
    175         Iterator<SessionInfo> it = list.iterator();
    176         while (it.hasNext()) {
    177             if (verify(it.next()) == null) {
    178                 it.remove();
    179             }
    180         }
    181         return list;
    182     }
    183 }
    184