12465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer/*
22465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * Copyright (C) 2015 The Android Open Source Project
32465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer *
42465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License");
52465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * you may not use this file except in compliance with the License.
62465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * You may obtain a copy of the License at
72465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer *
82465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer *      http://www.apache.org/licenses/LICENSE-2.0
92465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer *
102465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * Unless required by applicable law or agreed to in writing, software
112465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS,
122465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * See the License for the specific language governing permissions and
142465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * limitations under the License.
152465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer */
162465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerpackage com.android.support.car.lenspicker;
172465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
182465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.app.Activity;
192465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.content.Intent;
202465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.content.SharedPreferences;
212465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.content.pm.PackageManager;
222465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.content.pm.ResolveInfo;
2361448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauerimport android.content.pm.ResolveInfo.DisplayNameComparator;
242465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.os.Bundle;
252465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.service.media.MediaBrowserService;
262465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.text.TextUtils;
272465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport android.util.Log;
28bfee8559eaca4b3ce0625bc55cc9eb76108e42c2Anthony Chen
29bfee8559eaca4b3ce0625bc55cc9eb76108e42c2Anthony Chenimport androidx.car.widget.DayNightStyle;
30bfee8559eaca4b3ce0625bc55cc9eb76108e42c2Anthony Chenimport androidx.car.widget.PagedListView;
312465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
322465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport java.util.ArrayList;
3361448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauerimport java.util.Collections;
342465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport java.util.HashMap;
352465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerimport java.util.List;
362465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
372465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer/**
382465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * An Activity to present the user with a list of applications that can be started for a given
392465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer * facet.
402465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer */
412465f273eb12ef26ae921ac82058534b71974178Rakesh Iyerpublic class LensPickerActivity extends Activity implements LensPickerSelectionHandler {
422465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private static final String TAG = "LensPickerActivity";
432465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private PackageManager mPackageManager;
442465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private SharedPreferences mSharedPrefs;
452465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
462465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private String mLastLaunchedFacetId;
472465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private String mLastLaunchedPackageName;
482465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private Intent mLastLaunchedIntent;
492465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
502465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private PagedListView mPagedListView;
512465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
522465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    @Override
532465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    protected void onCreate(Bundle savedInstanceState) {
542465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        super.onCreate(savedInstanceState);
552465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
562465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mPackageManager = getPackageManager();
572465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mSharedPrefs = LensPickerUtils.getFacetSharedPrefs(this);
582465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
592465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        setContentView(R.layout.lens_list);
602465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mPagedListView = (PagedListView) findViewById(R.id.list_view);
612465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        // Set this to light mode, since the scroll bar buttons always appear
622465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        // on top of a dark scrim.
63bfee8559eaca4b3ce0625bc55cc9eb76108e42c2Anthony Chen        mPagedListView.setDayNightStyle(DayNightStyle.ALWAYS_LIGHT);
642465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
65bfee8559eaca4b3ce0625bc55cc9eb76108e42c2Anthony Chen        findViewById(R.id.dismiss_area).setOnClickListener(v -> finish());
662465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
672465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
682465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    @Override
692465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    protected void onResume() {
702465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        super.onResume();
712465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
722465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Intent intent = getIntent();
732465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        String[] categories = intent.getStringArrayExtra(
742465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                LensPickerConstants.EXTRA_FACET_CATEGORIES);
752465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        String[] packages = intent.getStringArrayExtra(LensPickerConstants.EXTRA_FACET_PACKAGES);
762465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        String facetId = intent.getStringExtra(LensPickerConstants.EXTRA_FACET_ID);
772465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
782465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        List<ResolveInfo> resolveInfos = getComponents(packages, categories);
792465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
802465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        if (resolveInfos != null && resolveInfos.size() == 1) {
812465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            // Directly launch the package rather than showing a list of 1.
822465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            ResolveInfo rInfo = resolveInfos.get(0);
832465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            String packageName = LensPickerUtils.getPackageName(rInfo);
842465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            Intent launchIntent = LensPickerUtils.getLaunchIntent(packageName, rInfo,
85b05b6c6076eaa0d140c95e6594f7e9998f14416aRakesh Iyer                    mPackageManager);
862465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            if (launchIntent != null) {
872465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                launch(facetId, packageName, launchIntent);
882465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            } else {
892465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                Log.e(TAG, "Failed to get launch intent for package" + packageName);
902465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            }
912465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            finish();
922465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            return;
932465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
942465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
952465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mPagedListView.setAdapter(new LensPickerAdapter(this, resolveInfos, facetId,
962465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                this /* LensPickerSelectionHandler */));
972465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
982465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
992465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    @Override
1002465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    protected void onPause() {
1012465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        super.onPause();
1022465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1032465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        if (mLastLaunchedFacetId == null || mLastLaunchedPackageName == null
1042465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                || mLastLaunchedIntent == null) {
1052465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            return;
1062465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1072465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1082465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        LensPickerUtils.saveLastLaunchedAppInfo(mSharedPrefs, mLastLaunchedFacetId,
1092465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                mLastLaunchedPackageName, mLastLaunchedIntent);
1102465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1112465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1122465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private boolean isReclick(Intent intent, Intent oldIntent) {
1132465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        String oldFacetId = oldIntent.getStringExtra(LensPickerConstants.EXTRA_FACET_ID);
1142465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        String newFacetId = intent.getStringExtra(LensPickerConstants.EXTRA_FACET_ID);
1152465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        return TextUtils.equals(oldFacetId, newFacetId);
1162465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1172465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1182465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    @Override
1192465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    protected void onNewIntent(Intent intent) {
1202465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Intent oldIntent = getIntent();
1212465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        setIntent(intent);
1222465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        if (isReclick(intent, oldIntent)) {
1232465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            finish();
1242465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1252465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1262465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1272465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private ArrayList<ResolveInfo> getComponents(String[] packages, String[] categories) {
1282465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        List<ResolveInfo> packageList = new ArrayList<>();
1292465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        if (packages != null) {
1302465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            for (int i = 0; i < packages.length; i++) {
1312465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                packageList.addAll(resolvePackage(packages[i]));
1322465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            }
1332465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1342465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1352465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        if (categories != null) {
1362465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            for (int i = 0; i < categories.length; i++) {
1372465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                packageList.addAll(resolveCategory(categories[i]));
1382465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1392465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                if (categories[i].equals(Intent.CATEGORY_APP_MUSIC)) {
1402465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                    packageList.addAll(resolveMediaBrowserServices());
1412465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                }
1422465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            }
1432465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1442465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1452465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        // De-dupe the list based on package names
1462465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        HashMap<String, ResolveInfo> dedupeList = new HashMap<>();
1472465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        for (ResolveInfo pkg : packageList) {
1482465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            String packageName = LensPickerUtils.getPackageName(pkg);
1492465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            if (!dedupeList.containsKey(packageName) || LensPickerUtils.isMediaService(pkg)) {
1502465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                dedupeList.put(packageName, pkg);
1512465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            }
1522465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1532465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1542465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        ArrayList<ResolveInfo> filteredPackageList = new ArrayList<>(dedupeList.values());
1552465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
1562465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            printResolveInfo("before dedupe", packageList);
1572465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            printResolveInfo("after dedupe", filteredPackageList);
1582465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1592465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
16061448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauer        // If presenting a category, alphabetize the list based on name.
16161448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauer        if (categories != null) {
16261448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauer            Collections.sort(filteredPackageList, new DisplayNameComparator(mPackageManager));
16361448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauer        }
16461448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauer
16561448e336b72d426e78d0d1bedb1a29fa10e42b2Nicholas Sauer
1662465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        return filteredPackageList;
1672465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1682465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1692465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private List<ResolveInfo> resolvePackage(String packageName) {
1702465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Intent intent = new Intent();
1712465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.setPackage(packageName);
1722465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.setAction(Intent.ACTION_MAIN);
1732465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.addCategory(Intent.CATEGORY_LAUNCHER);
1742465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        return mPackageManager.queryIntentActivities(intent, 0);
1752465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1762465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1772465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private List<ResolveInfo> resolveCategory(String category) {
1782465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Intent intent = new Intent();
1792465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.setAction(Intent.ACTION_MAIN);
1802465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.addCategory(Intent.CATEGORY_LAUNCHER);
1812465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.addCategory(category);
1822465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        return mPackageManager.queryIntentActivities(intent, 0);
1832465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1842465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1852465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private List<ResolveInfo> resolveMediaBrowserServices() {
1862465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Intent intent = new Intent();
1872465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        intent.setAction(MediaBrowserService.SERVICE_INTERFACE);
1882465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        return mPackageManager.queryIntentServices(intent, PackageManager.GET_RESOLVED_FILTER);
1892465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1902465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1912465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private void printResolveInfo(String title, List<ResolveInfo> list) {
1922465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        String names = "";
1932465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        for (ResolveInfo info : list) {
1942465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer            names += " " + LensPickerUtils.getPackageName(info);
1952465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        }
1962465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Log.d(TAG, title + " resolve info name: " + names);
1972465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
1982465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
1992465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    @Override
2002465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    public void onActivitySelected(LensPickerItem item) {
2012465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        Intent launchIntent = item.getLaunchIntent();
2022465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        launch(item.getFacetId(), launchIntent.getPackage(), launchIntent);
2032465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        finish();
2042465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
2052465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
2062465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    private void launch(String facetId, String packageName, Intent launchIntent) {
2072465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        // Save the information for the application that is about to be launched.
2082465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mLastLaunchedFacetId = facetId;
2092465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mLastLaunchedPackageName = packageName;
2102465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        mLastLaunchedIntent = launchIntent;
2112465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer
2122465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer        LensPickerUtils.launch(this /* context */, mSharedPrefs, facetId, packageName,
2132465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer                launchIntent);
2142465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer    }
2152465f273eb12ef26ae921ac82058534b71974178Rakesh Iyer}
216