SaveUi.java revision 7b7711680244108923f0dbb4ca6e35db7e659e6a
1/* 2 * Copyright (C) 2017 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 17package com.android.server.autofill.ui; 18 19import android.annotation.NonNull; 20import android.app.Dialog; 21import android.content.Context; 22import android.content.IntentSender; 23import android.os.Handler; 24import android.service.autofill.SaveInfo; 25import android.text.format.DateUtils; 26import android.view.Gravity; 27import android.view.Window; 28import android.view.WindowManager; 29import android.widget.TextView; 30import android.view.LayoutInflater; 31import android.view.View; 32 33import com.android.internal.R; 34import com.android.server.UiThread; 35 36/** 37 * Autofill Save Prompt 38 */ 39final class SaveUi { 40 public interface OnSaveListener { 41 void onSave(); 42 void onCancel(IntentSender listener); 43 void onDestroy(); 44 } 45 46 private final Handler mHandler = UiThread.getHandler(); 47 48 private final @NonNull Dialog mDialog; 49 50 private final @NonNull OnSaveListener mListener; 51 52 private boolean mDestroyed; 53 54 SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info, 55 @NonNull OnSaveListener listener, int lifeTimeMs) { 56 mListener = listener; 57 58 final LayoutInflater inflater = LayoutInflater.from(context); 59 final View view = inflater.inflate(R.layout.autofill_save, null); 60 61 final TextView titleView = (TextView) view.findViewById(R.id.autofill_save_title); 62 final String type; 63 64 switch(info.getType()) { 65 case SaveInfo.SAVE_DATA_TYPE_PASSWORD: 66 type = context.getString(R.string.autofill_save_type_password); 67 break; 68 case SaveInfo.SAVE_DATA_TYPE_ADDRESS: 69 type = context.getString(R.string.autofill_save_type_address); 70 break; 71 case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD: 72 type = context.getString(R.string.autofill_save_type_credit_card); 73 break; 74 default: 75 type = null; 76 } 77 78 final String title = (type == null) 79 ? context.getString(R.string.autofill_save_title, providerLabel) 80 : context.getString(R.string.autofill_save_title_with_type, type, providerLabel); 81 82 titleView.setText(title); 83 final CharSequence subTitle = info.getDescription(); 84 if (subTitle != null) { 85 final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle); 86 subTitleView.setText(subTitle); 87 subTitleView.setVisibility(View.VISIBLE); 88 } 89 90 final TextView noButton = view.findViewById(R.id.autofill_save_no); 91 if (info.getNegativeActionTitle() != null) { 92 noButton.setText(info.getNegativeActionTitle()); 93 noButton.setOnClickListener((v) -> mListener.onCancel( 94 info.getNegativeActionListener())); 95 } else { 96 noButton.setOnClickListener((v) -> mListener.onCancel(null)); 97 } 98 99 final View yesButton = view.findViewById(R.id.autofill_save_yes); 100 yesButton.setOnClickListener((v) -> mListener.onSave()); 101 102 final View closeButton = view.findViewById(R.id.autofill_save_close); 103 closeButton.setOnClickListener((v) -> mListener.onCancel(null)); 104 105 mDialog = new Dialog(context, R.style.Theme_Material_Panel); 106 mDialog.setContentView(view); 107 108 final Window window = mDialog.getWindow(); 109 window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); 110 window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 111 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 112 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 113 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); 114 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); 115 window.setGravity(Gravity.BOTTOM | Gravity.CENTER); 116 window.setCloseOnTouchOutside(true); 117 window.getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT; 118 119 mDialog.show(); 120 121 mHandler.postDelayed(() -> mListener.onCancel(null), lifeTimeMs); 122 } 123 124 void destroy() { 125 throwIfDestroyed(); 126 mListener.onDestroy(); 127 mHandler.removeCallbacksAndMessages(mListener); 128 mDialog.dismiss(); 129 mDestroyed = true; 130 } 131 132 private void throwIfDestroyed() { 133 if (mDestroyed) { 134 throw new IllegalStateException("cannot interact with a destroyed instance"); 135 } 136 } 137} 138