Adds autofill save ui
Test: Manual verification of save ui Test: CtsAutoFillServiceTestCases passes BUG: 31001899 Change-Id: Ibb154fc6108f20e6a1b889549bd264e8b80f2f0c
This commit is contained in:
parent
bd00fef41c
commit
87af2d8596
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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user