Home | History | Annotate | Download | only in autofill
      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.android.tv.settings.autofill;
     18 
     19 import android.Manifest;
     20 import android.content.ComponentName;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.pm.PackageManager;
     24 import android.content.pm.ResolveInfo;
     25 import android.content.pm.ServiceInfo;
     26 import android.provider.Settings;
     27 import android.service.autofill.AutofillService;
     28 import android.service.autofill.AutofillServiceInfo;
     29 import android.support.annotation.NonNull;
     30 import android.support.annotation.Nullable;
     31 import android.text.TextUtils;
     32 import android.util.Log;
     33 
     34 import com.android.settingslib.applications.DefaultAppInfo;
     35 import com.android.settingslib.wrapper.PackageManagerWrapper;
     36 
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 
     40 /**
     41  * Helper class for autofill related settings.
     42  */
     43 public class AutofillHelper {
     44 
     45     private static final String TAG = "AutofillHelper";
     46     static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
     47 
     48     /**
     49      * Get a list of autofill services.
     50      */
     51     @NonNull
     52     public static List<DefaultAppInfo> getAutofillCandidates(@NonNull Context context,
     53             @NonNull PackageManagerWrapper pm, int myUserId) {
     54         final List<DefaultAppInfo> candidates = new ArrayList<>();
     55         final List<ResolveInfo> resolveInfos = pm.queryIntentServices(
     56                 AUTOFILL_PROBE, PackageManager.GET_META_DATA);
     57         for (ResolveInfo info : resolveInfos) {
     58             final String permission = info.serviceInfo.permission;
     59             if (Manifest.permission.BIND_AUTOFILL_SERVICE.equals(permission)
     60                     || Manifest.permission.BIND_AUTOFILL.equals(permission)) {
     61                 candidates.add(new DefaultAppInfo(context, pm, myUserId, new ComponentName(
     62                         info.serviceInfo.packageName, info.serviceInfo.name)));
     63             }
     64         }
     65         return candidates;
     66     }
     67 
     68     /**
     69      * Get flattened ComponentName of current autofill service
     70      */
     71     @Nullable
     72     public static String getCurrentAutofill(@NonNull Context context) {
     73         return Settings.Secure.getString(context.getContentResolver(),
     74                 Settings.Secure.AUTOFILL_SERVICE);
     75     }
     76 
     77     /**
     78      * Get flattened ComponentName of current autofill service
     79      */
     80     @Nullable
     81     public static ComponentName getCurrentAutofillAsComponentName(@NonNull Context context) {
     82         String flattenedName = getCurrentAutofill(context);
     83         return TextUtils.isEmpty(flattenedName)
     84                 ? null : ComponentName.unflattenFromString(flattenedName);
     85     }
     86 
     87     /**
     88      * Find the current autofill service from the list.
     89      */
     90     @Nullable
     91     public static DefaultAppInfo getCurrentAutofill(@NonNull Context context,
     92             @NonNull List<DefaultAppInfo> candidates) {
     93         final ComponentName name = getCurrentAutofillAsComponentName(context);
     94         for (int i = 0; i < candidates.size(); i++) {
     95             DefaultAppInfo appInfo = candidates.get(i);
     96             if ((name == null && appInfo.componentName == null)
     97                     || (name != null && name.equals(appInfo.componentName))) {
     98                 return appInfo;
     99             }
    100         }
    101         return null;
    102     }
    103 
    104     /**
    105      * Get the Intent for settings activity of autofill service. Returns null if does not exist.
    106      */
    107     @Nullable
    108     public static Intent getAutofillSettingsIntent(@NonNull Context context,
    109             @NonNull PackageManagerWrapper pm, @Nullable DefaultAppInfo appInfo) {
    110         if (appInfo == null || appInfo.componentName == null) {
    111             return null;
    112         }
    113         String plattenString = appInfo.componentName.flattenToString();
    114         final List<ResolveInfo> resolveInfos = pm.queryIntentServices(
    115                 AUTOFILL_PROBE, PackageManager.GET_META_DATA);
    116 
    117         for (ResolveInfo resolveInfo : resolveInfos) {
    118             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    119             final String flattenKey = new ComponentName(
    120                     serviceInfo.packageName, serviceInfo.name).flattenToString();
    121             if (TextUtils.equals(plattenString, flattenKey)) {
    122                 final String settingsActivity;
    123                 try {
    124                     settingsActivity = new AutofillServiceInfo(context, serviceInfo)
    125                             .getSettingsActivity();
    126                 } catch (SecurityException e) {
    127                     // Service does not declare the proper permission, ignore it.
    128                     Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
    129                     return null;
    130                 }
    131                 if (TextUtils.isEmpty(settingsActivity)) {
    132                     return null;
    133                 }
    134                 return new Intent(Intent.ACTION_MAIN).setComponent(
    135                         new ComponentName(serviceInfo.packageName, settingsActivity));
    136             }
    137         }
    138 
    139         return null;
    140     }
    141 
    142     /**
    143      * Set autofill service and write to settings.
    144      */
    145     public static void setCurrentAutofill(@NonNull Context context, @Nullable String id) {
    146         if (id == null) {
    147             throw new IllegalArgumentException("Null ID");
    148         }
    149         Settings.Secure.putString(context.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE,
    150                 id);
    151     }
    152 
    153 }
    154