1 /**
2  * Copyright (c) 2018 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.example.android.multidisplay.launcher;
18 
19 import android.app.Application;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.os.AsyncTask;
27 
28 import androidx.lifecycle.AndroidViewModel;
29 import androidx.lifecycle.LiveData;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 /**
35  * A view model that provides a list of activities that can be launched.
36  */
37 public class AppListViewModel extends AndroidViewModel {
38 
39     private final AppListLiveData mLiveData;
40     private final PackageIntentReceiver mPackageIntentReceiver;
41 
AppListViewModel(Application application)42     public AppListViewModel(Application application) {
43         super(application);
44         mLiveData = new AppListLiveData(application);
45         mPackageIntentReceiver = new PackageIntentReceiver(mLiveData, application);
46     }
47 
getAppList()48     public LiveData<List<AppEntry>> getAppList() {
49         return mLiveData;
50     }
51 
onCleared()52     protected void onCleared() {
53         getApplication().unregisterReceiver(mPackageIntentReceiver);
54     }
55 }
56 
57 class AppListLiveData extends LiveData<List<AppEntry>> {
58 
59     private final PackageManager mPackageManager;
60     private int mCurrentDataVersion;
61 
AppListLiveData(Context context)62     public AppListLiveData(Context context) {
63         mPackageManager = context.getPackageManager();
64         loadData();
65     }
66 
loadData()67     void loadData() {
68         final int loadDataVersion = ++mCurrentDataVersion;
69 
70         new AsyncTask<Void, Void, List<AppEntry>>() {
71             @Override
72             protected List<AppEntry> doInBackground(Void... voids) {
73                 Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
74                 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
75 
76                 List<ResolveInfo> apps = mPackageManager.queryIntentActivities(mainIntent,
77                         PackageManager.GET_META_DATA);
78 
79                 List<AppEntry> entries = new ArrayList<>();
80                 if (apps != null) {
81                     for (ResolveInfo app : apps) {
82                         AppEntry entry = new AppEntry(app, mPackageManager);
83                         entries.add(entry);
84                     }
85                 }
86                 return entries;
87             }
88 
89             @Override
90             protected void onPostExecute(List<AppEntry> data) {
91                 if (mCurrentDataVersion == loadDataVersion) {
92                     setValue(data);
93                 }
94             }
95         }.execute();
96     }
97 }
98 
99 /**
100  * Receiver used to notify live data about app list changes.
101  */
102 class PackageIntentReceiver extends BroadcastReceiver {
103 
104     private final AppListLiveData mLiveData;
105 
PackageIntentReceiver(AppListLiveData liveData, Context context)106     public PackageIntentReceiver(AppListLiveData liveData, Context context) {
107         mLiveData = liveData;
108         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
109         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
110         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
111         filter.addDataScheme("package");
112         context.registerReceiver(this, filter);
113 
114         // Register for events related to sdcard installation.
115         IntentFilter sdFilter = new IntentFilter();
116         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
117         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
118         context.registerReceiver(this, sdFilter);
119     }
120 
121     @Override
onReceive(Context context, Intent intent)122     public void onReceive(Context context, Intent intent) {
123         mLiveData.loadData();
124     }
125 }