Home | History | Annotate | Download | only in carlauncher
      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 package com.android.car.carlauncher;
     17 
     18 import android.annotation.Nullable;
     19 import android.app.Activity;
     20 import android.car.Car;
     21 import android.car.CarNotConnectedException;
     22 import android.car.content.pm.CarPackageManager;
     23 import android.car.drivingstate.CarUxRestrictionsManager;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.ServiceConnection;
     30 import android.content.pm.LauncherApps;
     31 import android.content.pm.PackageManager;
     32 import android.os.Bundle;
     33 import android.os.IBinder;
     34 import android.text.Editable;
     35 import android.text.TextUtils;
     36 import android.text.TextWatcher;
     37 import android.util.Log;
     38 import android.view.View;
     39 import android.view.inputmethod.InputMethodManager;
     40 import android.widget.EditText;
     41 
     42 import java.util.List;
     43 
     44 import androidx.car.widget.PagedListView;
     45 
     46 /**
     47  * Activity that allows user to search in apps.
     48  */
     49 public final class AppSearchActivity extends Activity {
     50 
     51     private static final String TAG = "AppSearchActivity";
     52 
     53     private PackageManager mPackageManager;
     54     private SearchResultAdapter mSearchResultAdapter;
     55     private AppInstallUninstallReceiver mInstallUninstallReceiver;
     56     private Car mCar;
     57     private CarPackageManager mCarPackageManager;
     58     private CarUxRestrictionsManager mCarUxRestrictionsManager;
     59 
     60     private ServiceConnection mCarConnectionListener = new ServiceConnection() {
     61         @Override
     62         public void onServiceConnected(ComponentName name, IBinder service) {
     63             try {
     64                 mCarUxRestrictionsManager = (CarUxRestrictionsManager) mCar.getCarManager(
     65                         Car.CAR_UX_RESTRICTION_SERVICE);
     66                 mSearchResultAdapter.setIsDistractionOptimizationRequired(
     67                         mCarUxRestrictionsManager
     68                                 .getCurrentCarUxRestrictions()
     69                                 .isRequiresDistractionOptimization());
     70                 mCarUxRestrictionsManager.registerListener(
     71                         restrictionInfo ->
     72                                 mSearchResultAdapter.setIsDistractionOptimizationRequired(
     73                                         restrictionInfo.isRequiresDistractionOptimization()));
     74 
     75                 mCarPackageManager = (CarPackageManager) mCar.getCarManager(Car.PACKAGE_SERVICE);
     76                 mSearchResultAdapter.setAllApps(getAllApps());
     77             } catch (CarNotConnectedException e) {
     78                 Log.e(TAG, "Car not connected in CarConnectionListener", e);
     79             }
     80         }
     81 
     82         @Override
     83         public void onServiceDisconnected(ComponentName name) {
     84             mCarUxRestrictionsManager = null;
     85             mCarPackageManager = null;
     86         }
     87     };
     88 
     89     @Override
     90     protected void onCreate(@Nullable Bundle savedInstanceState) {
     91         super.onCreate(savedInstanceState);
     92         mPackageManager = getPackageManager();
     93         mCar = Car.createCar(this, mCarConnectionListener);
     94 
     95         setContentView(R.layout.app_search_activity);
     96         findViewById(R.id.container).setOnTouchListener(
     97                 (view, event) -> {
     98                     hideKeyboard();
     99                     return false;
    100                 });
    101         findViewById(R.id.exit_button_container).setOnClickListener(view -> finish());
    102 
    103         PagedListView searchResultView = findViewById(R.id.search_result);
    104         searchResultView.setClipToOutline(true);
    105         mSearchResultAdapter = new SearchResultAdapter(this);
    106         searchResultView.setAdapter(mSearchResultAdapter);
    107 
    108         EditText searchBar = findViewById(R.id.app_search_bar);
    109         searchBar.addTextChangedListener(new TextWatcher() {
    110             @Override
    111             public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    112             }
    113 
    114             @Override
    115             public void onTextChanged(CharSequence s, int start, int before, int count) {
    116             }
    117 
    118             @Override
    119             public void afterTextChanged(Editable s) {
    120                 if (TextUtils.isEmpty(s)) {
    121                     searchResultView.setVisibility(View.GONE);
    122                     mSearchResultAdapter.clearResults();
    123                 } else {
    124                     searchResultView.setVisibility(View.VISIBLE);
    125                     mSearchResultAdapter.getFilter().filter(s.toString());
    126                 }
    127             }
    128         });
    129     }
    130 
    131     @Override
    132     protected void onStart() {
    133         super.onStart();
    134         // register broadcast receiver for package installation and uninstallation
    135         mInstallUninstallReceiver = new AppInstallUninstallReceiver();
    136         IntentFilter filter = new IntentFilter();
    137         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
    138         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    139         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
    140         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    141         filter.addDataScheme("package");
    142         registerReceiver(mInstallUninstallReceiver, filter);
    143 
    144         // Connect to car service
    145         mCar.connect();
    146     }
    147 
    148     @Override
    149     protected void onStop() {
    150         super.onPause();
    151         // disconnect from app install/uninstall receiver
    152         if (mInstallUninstallReceiver != null) {
    153             unregisterReceiver(mInstallUninstallReceiver);
    154             mInstallUninstallReceiver = null;
    155         }
    156         // disconnect from car listeners
    157         try {
    158             if (mCarUxRestrictionsManager != null) {
    159                 mCarUxRestrictionsManager.unregisterListener();
    160             }
    161         } catch (CarNotConnectedException e) {
    162             Log.e(TAG, "Error unregistering listeners", e);
    163         }
    164         if (mCar != null) {
    165             mCar.disconnect();
    166         }
    167     }
    168 
    169     private List<AppMetaData> getAllApps() {
    170         return AppLauncherUtils.getAllLaunchableApps(
    171                 getSystemService(LauncherApps.class), mCarPackageManager, mPackageManager);
    172     }
    173 
    174     public void hideKeyboard() {
    175         InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(
    176                 Activity.INPUT_METHOD_SERVICE);
    177         inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    178     }
    179 
    180     private class AppInstallUninstallReceiver extends BroadcastReceiver {
    181         @Override
    182         public void onReceive(Context context, Intent intent) {
    183             String packageName = intent.getData().getSchemeSpecificPart();
    184 
    185             if (TextUtils.isEmpty(packageName)) {
    186                 Log.e(TAG, "System sent an empty app install/uninstall broadcast");
    187                 return;
    188             }
    189 
    190             mSearchResultAdapter.setAllApps(getAllApps());
    191         }
    192     }
    193 }
    194