1 /*
2  * Copyright (C) 2020 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.inlinefillservice;
18 
19 import static android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT;
20 
21 import android.app.Activity;
22 import android.app.PendingIntent;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentSender;
26 import android.os.Bundle;
27 import android.os.Parcelable;
28 import android.service.autofill.Dataset;
29 import android.service.autofill.FillResponse;
30 import android.util.ArrayMap;
31 import android.view.autofill.AutofillId;
32 import android.view.inputmethod.InlineSuggestionsRequest;
33 
34 import androidx.annotation.NonNull;
35 import androidx.annotation.Nullable;
36 
37 import java.util.Optional;
38 
39 /**
40  * Activity used for autofill authentication, it simply sets the dataste upon tapping OK.
41  */
42 // TODO(b/114236837): should display a small dialog, not take the full screen
43 public class AuthActivity extends Activity {
44 
45     private static final String EXTRA_DATASET = "dataset";
46     private static final String EXTRA_HINTS = "hints";
47     private static final String EXTRA_IDS = "ids";
48     private static final String EXTRA_AUTH_DATASETS = "auth_datasets";
49     private static final String EXTRA_INLINE_REQUEST = "inline_request";
50 
51     private static int sPendingIntentId = 0;
52 
53     @Override
onCreate(Bundle savedInstanceState)54     protected void onCreate(Bundle savedInstanceState) {
55         super.onCreate(savedInstanceState);
56         setContentView(R.layout.auth_activity);
57         findViewById(R.id.yes).setOnClickListener((view) -> onYes());
58         findViewById(R.id.no).setOnClickListener((view) -> onNo());
59     }
60 
onYes()61     private void onYes() {
62         Intent myIntent = getIntent();
63         Intent replyIntent = new Intent();
64         Dataset dataset = myIntent.getParcelableExtra(EXTRA_DATASET);
65         if (dataset != null) {
66             replyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset);
67         } else {
68             String[] hints = myIntent.getStringArrayExtra(EXTRA_HINTS);
69             Parcelable[] ids = myIntent.getParcelableArrayExtra(EXTRA_IDS);
70             boolean authenticateDatasets = myIntent.getBooleanExtra(EXTRA_AUTH_DATASETS, false);
71             final InlineSuggestionsRequest inlineRequest =
72                     myIntent.getParcelableExtra(EXTRA_INLINE_REQUEST);
73             int size = hints.length;
74             ArrayMap<String, AutofillId> fields = new ArrayMap<>(size);
75             for (int i = 0; i < size; i++) {
76                 fields.put(hints[i], (AutofillId) ids[i]);
77             }
78             FillResponse response =
79                     InlineFillService.createResponse(this, fields, 1, authenticateDatasets,
80                             Optional.ofNullable(inlineRequest));
81             replyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, response);
82         }
83         setResult(RESULT_OK, replyIntent);
84         finish();
85     }
86 
onNo()87     private void onNo() {
88         setResult(RESULT_CANCELED);
89         finish();
90     }
91 
newIntentSenderForDataset(@onNull Context context, @NonNull Dataset dataset)92     public static IntentSender newIntentSenderForDataset(@NonNull Context context,
93             @NonNull Dataset dataset) {
94         return newIntentSender(context, dataset, null, null, false, null);
95     }
96 
newIntentSenderForResponse(@onNull Context context, @NonNull String[] hints, @NonNull AutofillId[] ids, boolean authenticateDatasets, @Nullable InlineSuggestionsRequest inlineRequest)97     public static IntentSender newIntentSenderForResponse(@NonNull Context context,
98             @NonNull String[] hints, @NonNull AutofillId[] ids, boolean authenticateDatasets,
99             @Nullable InlineSuggestionsRequest inlineRequest) {
100         return newIntentSender(context, null, hints, ids, authenticateDatasets, inlineRequest);
101     }
102 
newIntentSender(@onNull Context context, @Nullable Dataset dataset, @Nullable String[] hints, @Nullable AutofillId[] ids, boolean authenticateDatasets, @Nullable InlineSuggestionsRequest inlineRequest)103     private static IntentSender newIntentSender(@NonNull Context context,
104             @Nullable Dataset dataset, @Nullable String[] hints, @Nullable AutofillId[] ids,
105             boolean authenticateDatasets, @Nullable InlineSuggestionsRequest inlineRequest) {
106         Intent intent = new Intent(context, AuthActivity.class);
107         if (dataset != null) {
108             intent.putExtra(EXTRA_DATASET, dataset);
109         } else {
110             intent.putExtra(EXTRA_HINTS, hints);
111             intent.putExtra(EXTRA_IDS, ids);
112             intent.putExtra(EXTRA_AUTH_DATASETS, authenticateDatasets);
113             intent.putExtra(EXTRA_INLINE_REQUEST, inlineRequest);
114         }
115 
116         return PendingIntent.getActivity(context, ++sPendingIntentId, intent,
117                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE).getIntentSender();
118     }
119 }
120