• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.android.systemui.statusbar.policy;
18 
19 import com.android.systemui.R;
20 
21 import android.annotation.NonNull;
22 import android.app.Notification;
23 import android.app.PendingIntent;
24 import android.app.RemoteInput;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.graphics.drawable.Drawable;
28 import android.os.Bundle;
29 import android.util.AttributeSet;
30 import android.util.Log;
31 import android.view.KeyEvent;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.view.inputmethod.EditorInfo;
36 import android.view.inputmethod.InputMethodManager;
37 import android.widget.EditText;
38 import android.widget.FrameLayout;
39 import android.widget.ProgressBar;
40 import android.widget.TextView;
41 
42 /**
43  * Host for the remote input.
44  */
45 public class RemoteInputView extends FrameLayout implements View.OnClickListener {
46 
47     private static final String TAG = "RemoteInput";
48 
49     private RemoteEditText mEditText;
50     private ProgressBar mProgressBar;
51     private PendingIntent mPendingIntent;
52     private RemoteInput mRemoteInput;
53     private Notification.Action mAction;
54 
RemoteInputView(Context context, AttributeSet attrs)55     public RemoteInputView(Context context, AttributeSet attrs) {
56         super(context, attrs);
57     }
58 
59     @Override
onFinishInflate()60     protected void onFinishInflate() {
61         super.onFinishInflate();
62 
63         mProgressBar = (ProgressBar) findViewById(R.id.remote_input_progress);
64 
65         mEditText = (RemoteEditText) getChildAt(0);
66         mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
67             @Override
68             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
69 
70                 // Check if this was the result of hitting the enter key
71                 final boolean isSoftImeEvent = event == null
72                         && (actionId == EditorInfo.IME_ACTION_DONE
73                         || actionId == EditorInfo.IME_ACTION_NEXT
74                         || actionId == EditorInfo.IME_ACTION_SEND);
75                 final boolean isKeyboardEnterKey = event != null
76                         && KeyEvent.isConfirmKey(event.getKeyCode())
77                         && event.getAction() == KeyEvent.ACTION_DOWN;
78 
79                 if (isSoftImeEvent || isKeyboardEnterKey) {
80                     sendRemoteInput();
81                     return true;
82                 }
83                 return false;
84             }
85         });
86         mEditText.setOnClickListener(this);
87         mEditText.setInnerFocusable(false);
88     }
89 
sendRemoteInput()90     private void sendRemoteInput() {
91         Bundle results = new Bundle();
92         results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
93         Intent fillInIntent = new Intent();
94         RemoteInput.addResultsToIntent(mAction.getRemoteInputs(), fillInIntent,
95                 results);
96 
97         mEditText.setEnabled(false);
98         mProgressBar.setVisibility(VISIBLE);
99 
100         try {
101             mPendingIntent.send(mContext, 0, fillInIntent);
102         } catch (PendingIntent.CanceledException e) {
103             Log.i(TAG, "Unable to send remote input result", e);
104         }
105     }
106 
inflate(Context context, ViewGroup root, Notification.Action action, RemoteInput remoteInput)107     public static RemoteInputView inflate(Context context, ViewGroup root,
108             Notification.Action action, RemoteInput remoteInput) {
109         RemoteInputView v = (RemoteInputView)
110                 LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
111 
112         v.mEditText.setHint(action.title);
113         v.mPendingIntent = action.actionIntent;
114         v.mRemoteInput = remoteInput;
115         v.mAction = action;
116 
117         return v;
118     }
119 
120     @Override
onClick(View v)121     public void onClick(View v) {
122         if (v == mEditText) {
123             if (!mEditText.isFocusable()) {
124                 mEditText.setInnerFocusable(true);
125                 InputMethodManager imm = InputMethodManager.getInstance();
126                 if (imm != null) {
127                     imm.viewClicked(mEditText);
128                     imm.showSoftInput(mEditText, 0);
129                 }
130             }
131         }
132     }
133 
134     /**
135      * An EditText that changes appearance based on whether it's focusable and becomes
136      * un-focusable whenever the user navigates away from it or it becomes invisible.
137      */
138     public static class RemoteEditText extends EditText {
139 
140         private final Drawable mBackground;
141 
RemoteEditText(Context context, AttributeSet attrs)142         public RemoteEditText(Context context, AttributeSet attrs) {
143             super(context, attrs);
144             mBackground = getBackground();
145         }
146 
defocusIfNeeded()147         private void defocusIfNeeded() {
148             if (isFocusable() && isEnabled()) {
149                 setInnerFocusable(false);
150             }
151         }
152 
153         @Override
onVisibilityChanged(View changedView, int visibility)154         protected void onVisibilityChanged(View changedView, int visibility) {
155             super.onVisibilityChanged(changedView, visibility);
156 
157             if (!isShown()) {
158                 defocusIfNeeded();
159             }
160         }
161 
162         @Override
onFocusLost()163         protected void onFocusLost() {
164             super.onFocusLost();
165             defocusIfNeeded();
166         }
167 
168         @Override
onKeyPreIme(int keyCode, KeyEvent event)169         public boolean onKeyPreIme(int keyCode, KeyEvent event) {
170             if (keyCode == KeyEvent.KEYCODE_BACK) {
171                 defocusIfNeeded();
172             }
173             return super.onKeyPreIme(keyCode, event);
174         }
175 
176 
setInnerFocusable(boolean focusable)177         void setInnerFocusable(boolean focusable) {
178             setFocusableInTouchMode(focusable);
179             setFocusable(focusable);
180             setCursorVisible(focusable);
181 
182             if (focusable) {
183                 requestFocus();
184                 setBackground(mBackground);
185             } else {
186                 setBackground(null);
187             }
188 
189         }
190     }
191 }
192