SaveUi.java revision de4d4c2083a07b4d99eaec6985ca4527d5e48e4d
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 } 44 45 private final Handler mHandler = UiThread.getHandler(); 46 47 private final @NonNull Dialog mDialog; 48 49 private final @NonNull OnSaveListener mListener; 50 51 private boolean mDestroyed; 52 53 SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info, 54 @NonNull OnSaveListener listener, int lifeTimeMs) { 55 mListener = listener; 56 57 final LayoutInflater inflater = LayoutInflater.from(context); 58 final View view = inflater.inflate(R.layout.autofill_save, null); 59 60 final TextView titleView = (TextView) view.findViewById(R.id.autofill_save_title); 61 final String type; 62 63 switch(info.getType()) { 64 case SaveInfo.SAVE_DATA_TYPE_PASSWORD: 65 type = context.getString(R.string.autofill_save_type_password); 66 break; 67 case SaveInfo.SAVE_DATA_TYPE_ADDRESS: 68 type = context.getString(R.string.autofill_save_type_address); 69 break; 70 case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD: 71 type = context.getString(R.string.autofill_save_type_credit_card); 72 break; 73 default: 74 type = null; 75 } 76 77 final String title = (type == null) 78 ? context.getString(R.string.autofill_save_title, providerLabel) 79 : context.getString(R.string.autofill_save_title_with_type, type, providerLabel); 80 81 titleView.setText(title); 82 final CharSequence subTitle = info.getDescription(); 83 if (subTitle != null) { 84 final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle); 85 subTitleView.setText(subTitle); 86 subTitleView.setVisibility(View.VISIBLE); 87 } 88 89 final TextView noButton = view.findViewById(R.id.autofill_save_no); 90 if (info.getNegativeActionTitle() != null) { 91 noButton.setText(info.getNegativeActionTitle()); 92 noButton.setOnClickListener((v) -> mListener.onCancel( 93 info.getNegativeActionListener())); 94 } else { 95 noButton.setOnClickListener((v) -> mListener.onCancel(null)); 96 } 97 98 final View yesButton = view.findViewById(R.id.autofill_save_yes); 99 yesButton.setOnClickListener((v) -> mListener.onSave()); 100 101 final View closeButton = view.findViewById(R.id.autofill_save_close); 102 closeButton.setOnClickListener((v) -> mListener.onCancel(null)); 103 104 mDialog = new Dialog(context, R.style.Theme_Material_Panel); 105 mDialog.setContentView(view); 106 107 final Window window = mDialog.getWindow(); 108 window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); 109 window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 110 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 111 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 112 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); 113 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); 114 window.setGravity(Gravity.BOTTOM | Gravity.CENTER); 115 window.setCloseOnTouchOutside(true); 116 window.getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT; 117 118 mDialog.show(); 119 120 mHandler.postDelayed(() -> mListener.onCancel(null), lifeTimeMs); 121 } 122 123 void destroy() { 124 throwIfDestroyed(); 125 mHandler.removeCallbacksAndMessages(mListener); 126 mDialog.dismiss(); 127 mDestroyed = true; 128 } 129 130 private void throwIfDestroyed() { 131 if (mDestroyed) { 132 throw new IllegalStateException("cannot interact with a destroyed instance"); 133 } 134 } 135} 136