1/*
2 * Copyright (C) 2015 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 */
16package com.android.support.car.lenspicker;
17
18import android.app.Activity;
19import android.content.Intent;
20import android.content.SharedPreferences;
21import android.content.pm.PackageManager;
22import android.content.pm.ResolveInfo;
23import android.content.pm.ResolveInfo.DisplayNameComparator;
24import android.os.Bundle;
25import android.service.media.MediaBrowserService;
26import android.text.TextUtils;
27import android.util.Log;
28import android.view.View;
29
30import com.android.car.view.PagedListView;
31
32import java.util.ArrayList;
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.List;
36
37/**
38 * An Activity to present the user with a list of applications that can be started for a given
39 * facet.
40 */
41public class LensPickerActivity extends Activity implements LensPickerSelectionHandler {
42    private static final String TAG = "LensPickerActivity";
43    private PackageManager mPackageManager;
44    private SharedPreferences mSharedPrefs;
45
46    private String mLastLaunchedFacetId;
47    private String mLastLaunchedPackageName;
48    private Intent mLastLaunchedIntent;
49
50    private PagedListView mPagedListView;
51
52    @Override
53    protected void onCreate(Bundle savedInstanceState) {
54        super.onCreate(savedInstanceState);
55
56        mPackageManager = getPackageManager();
57        mSharedPrefs = LensPickerUtils.getFacetSharedPrefs(this);
58
59        setContentView(R.layout.lens_list);
60        mPagedListView = (PagedListView) findViewById(R.id.list_view);
61        // Set this to light mode, since the scroll bar buttons always appear
62        // on top of a dark scrim.
63        mPagedListView.setLightMode();
64
65        findViewById(R.id.dismiss_area).setOnClickListener(new View.OnClickListener() {
66            @Override
67            public void onClick(View v) {
68                finish();
69            }
70        });
71    }
72
73    @Override
74    protected void onResume() {
75        super.onResume();
76
77        Intent intent = getIntent();
78        String[] categories = intent.getStringArrayExtra(
79                LensPickerConstants.EXTRA_FACET_CATEGORIES);
80        String[] packages = intent.getStringArrayExtra(LensPickerConstants.EXTRA_FACET_PACKAGES);
81        String facetId = intent.getStringExtra(LensPickerConstants.EXTRA_FACET_ID);
82
83        List<ResolveInfo> resolveInfos = getComponents(packages, categories);
84
85        if (resolveInfos != null && resolveInfos.size() == 1) {
86            // Directly launch the package rather than showing a list of 1.
87            ResolveInfo rInfo = resolveInfos.get(0);
88            String packageName = LensPickerUtils.getPackageName(rInfo);
89            Intent launchIntent = LensPickerUtils.getLaunchIntent(packageName, rInfo,
90                    mPackageManager);
91            if (launchIntent != null) {
92                launch(facetId, packageName, launchIntent);
93            } else {
94                Log.e(TAG, "Failed to get launch intent for package" + packageName);
95            }
96            finish();
97            return;
98        }
99
100        mPagedListView.setAdapter(new LensPickerAdapter(this, resolveInfos, facetId,
101                this /* LensPickerSelectionHandler */));
102    }
103
104    @Override
105    protected void onPause() {
106        super.onPause();
107
108        if (mLastLaunchedFacetId == null || mLastLaunchedPackageName == null
109                || mLastLaunchedIntent == null) {
110            return;
111        }
112
113        LensPickerUtils.saveLastLaunchedAppInfo(mSharedPrefs, mLastLaunchedFacetId,
114                mLastLaunchedPackageName, mLastLaunchedIntent);
115    }
116
117    private boolean isReclick(Intent intent, Intent oldIntent) {
118        String oldFacetId = oldIntent.getStringExtra(LensPickerConstants.EXTRA_FACET_ID);
119        String newFacetId = intent.getStringExtra(LensPickerConstants.EXTRA_FACET_ID);
120        return TextUtils.equals(oldFacetId, newFacetId);
121    }
122
123    @Override
124    protected void onNewIntent(Intent intent) {
125        Intent oldIntent = getIntent();
126        setIntent(intent);
127        if (isReclick(intent, oldIntent)) {
128            finish();
129        }
130    }
131
132    private ArrayList<ResolveInfo> getComponents(String[] packages, String[] categories) {
133        List<ResolveInfo> packageList = new ArrayList<>();
134        if (packages != null) {
135            for (int i = 0; i < packages.length; i++) {
136                packageList.addAll(resolvePackage(packages[i]));
137            }
138        }
139
140        if (categories != null) {
141            for (int i = 0; i < categories.length; i++) {
142                packageList.addAll(resolveCategory(categories[i]));
143
144                if (categories[i].equals(Intent.CATEGORY_APP_MUSIC)) {
145                    packageList.addAll(resolveMediaBrowserServices());
146                }
147            }
148        }
149
150        // De-dupe the list based on package names
151        HashMap<String, ResolveInfo> dedupeList = new HashMap<>();
152        for (ResolveInfo pkg : packageList) {
153            String packageName = LensPickerUtils.getPackageName(pkg);
154            if (!dedupeList.containsKey(packageName) || LensPickerUtils.isMediaService(pkg)) {
155                dedupeList.put(packageName, pkg);
156            }
157        }
158
159        ArrayList<ResolveInfo> filteredPackageList = new ArrayList<>(dedupeList.values());
160        if (Log.isLoggable(TAG, Log.DEBUG)) {
161            printResolveInfo("before dedupe", packageList);
162            printResolveInfo("after dedupe", filteredPackageList);
163        }
164
165        // If presenting a category, alphabetize the list based on name.
166        if (categories != null) {
167            Collections.sort(filteredPackageList, new DisplayNameComparator(mPackageManager));
168        }
169
170
171        return filteredPackageList;
172    }
173
174    private List<ResolveInfo> resolvePackage(String packageName) {
175        Intent intent = new Intent();
176        intent.setPackage(packageName);
177        intent.setAction(Intent.ACTION_MAIN);
178        intent.addCategory(Intent.CATEGORY_LAUNCHER);
179        return mPackageManager.queryIntentActivities(intent, 0);
180    }
181
182    private List<ResolveInfo> resolveCategory(String category) {
183        Intent intent = new Intent();
184        intent.setAction(Intent.ACTION_MAIN);
185        intent.addCategory(Intent.CATEGORY_LAUNCHER);
186        intent.addCategory(category);
187        return mPackageManager.queryIntentActivities(intent, 0);
188    }
189
190    private List<ResolveInfo> resolveMediaBrowserServices() {
191        Intent intent = new Intent();
192        intent.setAction(MediaBrowserService.SERVICE_INTERFACE);
193        return mPackageManager.queryIntentServices(intent, PackageManager.GET_RESOLVED_FILTER);
194    }
195
196    private void printResolveInfo(String title, List<ResolveInfo> list) {
197        String names = "";
198        for (ResolveInfo info : list) {
199            names += " " + LensPickerUtils.getPackageName(info);
200        }
201        Log.d(TAG, title + " resolve info name: " + names);
202    }
203
204    @Override
205    public void onActivitySelected(LensPickerItem item) {
206        Intent launchIntent = item.getLaunchIntent();
207        launch(item.getFacetId(), launchIntent.getPackage(), launchIntent);
208        finish();
209    }
210
211    private void launch(String facetId, String packageName, Intent launchIntent) {
212        // Save the information for the application that is about to be launched.
213        mLastLaunchedFacetId = facetId;
214        mLastLaunchedPackageName = packageName;
215        mLastLaunchedIntent = launchIntent;
216
217        LensPickerUtils.launch(this /* context */, mSharedPrefs, facetId, packageName,
218                launchIntent);
219    }
220}
221