Adds autofill save ui

Test: Manual verification of save ui
Test: CtsAutoFillServiceTestCases passes

BUG: 31001899
Change-Id: Ibb154fc6108f20e6a1b889549bd264e8b80f2f0c
This commit is contained in:
Felipe Leme 2017-01-26 16:52:12 -08:00
parent bd00fef41c
commit 87af2d8596
3 changed files with 153 additions and 10 deletions
services/autofill/java/com/android/server/autofill

@ -923,7 +923,7 @@ final class AutoFillManagerServiceImpl {
// TODO(b/33197203): temporarily hack: show the save notification after autofilled,
// since save is not automatically detected yet.
mUi.showSaveUI(mUserId, mId);
mUi.showSaveNotification(mUserId, mId); removeSelf = false;
} catch (RemoteException e) {
Slog.w(TAG, "Error auto-filling activity: " + e);

@ -29,12 +29,16 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Rect;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Bundle;
import android.util.Slog;
import android.view.autofill.AutoFillId;
import android.view.autofill.Dataset;
import android.view.autofill.FillResponse;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import com.android.internal.annotations.GuardedBy;
@ -53,8 +57,16 @@ final class AutoFillUI {
private final Context mContext;
private final WindowManager mWm;
/**
* Custom snackbar UI used for saving autofill or other informational messages.
*/
private View mSnackbar;
AutoFillUI(Context context, AutoFillManagerService service, Object lock) {
mContext = context;
mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mService = service;
mLock = lock;
@ -130,7 +142,20 @@ final class AutoFillUI {
* Shows the UI asking the user to save for auto-fill.
*/
void showSaveUI(int userId, int sessionId) {
showSaveNotification(userId, sessionId);
showSnackbar(new SavePrompt(mContext, new SavePrompt.OnSaveListener() {
@Override
public void onSaveClick() {
hideSnackbar();
synchronized (mLock) {
final AutoFillManagerServiceImpl service = getServiceLocked(userId);
service.requestSaveLocked(sessionId);
}
}
@Override
public void onCancelClick() {
hideSnackbar();
}
}));
}
/**
@ -158,10 +183,8 @@ final class AutoFillUI {
}
private void onSaveRequested(int userId, int sessionId) {
synchronized (mLock) {
final AutoFillManagerServiceImpl service = getServiceLocked(userId);
service.requestSaveLocked(sessionId);
}
// TODO(b/33197203): displays the snack bar, until save notification is refactored
showSaveUI(userId, sessionId);
}
private void onDatasetPicked(int userId, Dataset dataset, int sessionId) {
@ -191,6 +214,34 @@ final class AutoFillUI {
}
}
//similar to a snackbar, but can be a bit custom since it is more than just text. This will
//allow two buttons for saving or not saving the autofill for instance as well.
private void showSnackbar(View snackBar) {
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // TODO(b/33197203) use TYPE_AUTO_FILL
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.BOTTOM | Gravity.LEFT;
UiThread.getHandler().runWithScissors(() -> {
mSnackbar = snackBar;
mWm.addView(mSnackbar, params);
}, 0);
}
private void hideSnackbar() {
UiThread.getHandler().runWithScissors(() -> {
if (mSnackbar != null) {
mWm.removeView(mSnackbar);
mSnackbar = null;
}
}, 0);
}
/////////////////////////////////////////////////////////////////////////////////
// TODO(b/33197203): temporary code using a notification to request auto-fill. //
// Will be removed once UX decide the right way to present it to the user. //
@ -215,9 +266,9 @@ final class AutoFillUI {
private static final String TYPE_SAVE = "save";
private static final String TYPE_AUTH_RESPONSE = "auth_response";
@GuardedBy("mLock")
@GuardedBy("mServiceLock")
private BroadcastReceiver mNotificationReceiver;
@GuardedBy("mLock")
@GuardedBy("mServiceLock")
private final AutoFillManagerService mService;
private final Object mLock;
@ -403,8 +454,8 @@ final class AutoFillUI {
final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
++sResultCode, saveIntent, PendingIntent.FLAG_ONE_SHOT);
final String title = "AutoFill Save";
final String subTitle = "Tap notification to ask provider to save fields.";
final String title = "AutoFill Save Emulation";
final String subTitle = "Tap notification to launch the save snackbar.";
final Notification notification = newNotificationBuilder()
.setAutoCancel(true)

@ -0,0 +1,92 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.autofill;
import android.content.Context;
import android.graphics.Color;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import android.view.View;
/**
* Autofill Save Prompt
*/
final class SavePrompt extends RelativeLayout {
public interface OnSaveListener {
void onSaveClick();
void onCancelClick();
}
private final TextView mTextView;
private final TextView mNoButton;
private final TextView mYesButton;
private final OnSaveListener mListener;
SavePrompt(Context context, OnSaveListener listener) {
super(context);
mListener = listener;
setBackgroundColor(Color.YELLOW);
// TODO(b/33197203): move layout to XML
mTextView = new TextView(context);
final LayoutParams textParams = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
textParams.setMargins(50, 25, 50, 0);
mTextView.setLayoutParams(textParams);
// TODO(b/33197203): use R.string once final wording is done
mTextView.setText("Save for autofill?");
mTextView.setId(View.generateViewId());
mNoButton = new TextView(context);
// TODO(b/33197203): use R.string once final wording is done
mNoButton.setText("No thanks");
mNoButton.setBackgroundColor(Color.TRANSPARENT);
mNoButton.setAllCaps(true);
mNoButton.setOnClickListener((v) -> {
mListener.onCancelClick();
});
mYesButton = new TextView(context);
// TODO(b/33197203): use R.string once final wording is done
mYesButton.setText("Save");
mYesButton.setBackgroundColor(Color.TRANSPARENT);
mYesButton.setId(View.generateViewId());
mYesButton.setAllCaps(true);
mYesButton.setOnClickListener((v) -> {
mListener.onSaveClick();
});
addView(mTextView);
addView(mNoButton);
addView(mYesButton);
final LayoutParams yesLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
yesLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
yesLayoutParams.addRule(RelativeLayout.BELOW, mTextView.getId());
yesLayoutParams.setMargins(25, 25, 50, 25);
mYesButton.setLayoutParams(yesLayoutParams);
final LayoutParams noLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
noLayoutParams.addRule(RelativeLayout.LEFT_OF, mYesButton.getId());
noLayoutParams.addRule(RelativeLayout.BELOW, mTextView.getId());
noLayoutParams.setMargins(50, 25, 25, 25);
mNoButton.setLayoutParams(noLayoutParams);
}
}