1616
1717package com .android .inputmethod .tools .edittextvariations ;
1818
19+ import static android .graphics .Color .BLUE ;
20+ import static android .view .Gravity .LEFT ;
21+ import static android .view .Gravity .TOP ;
22+ import static android .view .WindowManager .LayoutParams .FLAG_ALT_FOCUSABLE_IM ;
23+ import static android .view .WindowManager .LayoutParams .FLAG_NOT_FOCUSABLE ;
24+ import static android .view .WindowManager .LayoutParams .FLAG_WATCH_OUTSIDE_TOUCH ;
25+ import static android .view .WindowManager .LayoutParams .TYPE_APPLICATION_OVERLAY ;
26+
27+ import android .Manifest ;
1928import android .annotation .SuppressLint ;
2029import android .app .Activity ;
2130import android .app .AlertDialog ;
31+ import android .content .Context ;
2232import android .content .DialogInterface ;
2333import android .content .Intent ;
2434import android .content .SharedPreferences ;
2535import android .content .pm .ApplicationInfo ;
2636import android .content .pm .PackageInfo ;
37+ import android .content .pm .PackageManager ;
2738import android .content .pm .PackageManager .NameNotFoundException ;
39+ import android .graphics .Rect ;
2840import android .os .Build ;
2941import android .os .Bundle ;
3042import android .preference .PreferenceManager ;
43+ import android .provider .Settings ;
3144import android .text .InputType ;
3245import android .text .TextUtils ;
3346import android .util .Log ;
4558import android .widget .AutoCompleteTextView ;
4659import android .widget .EditText ;
4760import android .widget .TextView ;
61+ import android .widget .Toast ;
4862
63+ import java .lang .reflect .Field ;
4964import java .util .ArrayList ;
5065import java .util .List ;
5166
@@ -61,9 +76,11 @@ public final class EditTextVariations extends Activity implements TextView.OnEdi
6176 private static final int MENU_SOFTINPUT_VISIBLE = 4 ;
6277 private static final int MENU_SOFTINPUT_HIDDEN = 5 ;
6378 private static final int MENU_DIRECT_REPLY = 6 ;
79+ private static final int MENU_TOGGLE_IME_FOCUSABLE_OVERLAY = 7 ;
6480 private static final String PREF_THEME = "theme" ;
6581 private static final String PREF_NAVIGATE = "navigate" ;
6682 private static final String PREF_SOFTINPUT = "softinput" ;
83+ private static final int NOTIFICATION_PERMISSION_REQUEST_CODE = 0 ;
6784
6885 private SharedPreferences prefs ;
6986 private View [] fields ;
@@ -80,6 +97,9 @@ public final class EditTextVariations extends Activity implements TextView.OnEdi
8097
8198 private ArrayAdapter <String > mAutoCompleteAdapter ;
8299
100+ private TextView mOverlayTextView ;
101+ private boolean mShowOverlay = true ;
102+
83103 /** Called when the activity is first created. */
84104 @ SuppressLint ("SetJavaScriptEnabled" )
85105 @ Override
@@ -166,9 +186,12 @@ public boolean onCreateOptionsMenu(final Menu menu) {
166186 if (NotificationUtils .DIRECT_REPLY_SUPPORTED ) {
167187 menu .add (Menu .NONE , MENU_DIRECT_REPLY , 5 , R .string .menu_direct_reply );
168188 }
189+ menu .add (Menu .NONE , MENU_TOGGLE_IME_FOCUSABLE_OVERLAY , 6 ,
190+ mShowOverlay ? getString (R .string .menu_show_ime_focusable_overlay )
191+ : getString (R .string .menu_hide_ime_focusable_overlay ));
169192 try {
170193 final PackageInfo pinfo = getPackageManager ().getPackageInfo (getPackageName (), 0 );
171- menu .add (Menu .NONE , MENU_VERSION , 6 ,
194+ menu .add (Menu .NONE , MENU_VERSION , 7 ,
172195 getString (R .string .menu_version , pinfo .versionName ))
173196 .setEnabled (false );
174197 } catch (NameNotFoundException e ) {
@@ -199,11 +222,53 @@ public boolean onOptionsItemSelected(final MenuItem item) {
199222 saveSoftInputMode (itemId == MENU_SOFTINPUT_VISIBLE );
200223 restartActivity ();
201224 } else if (itemId == MENU_DIRECT_REPLY ) {
202- NotificationUtils .sendDirectReplyNotification (this );
225+ final boolean needPermissionCheck = isNeedNotificationPermission ()
226+ && checkSelfPermission (Manifest .permission .POST_NOTIFICATIONS ) !=
227+ PackageManager .PERMISSION_GRANTED ;
228+ if (needPermissionCheck ) {
229+ requestPermissions (new String [] { Manifest .permission .POST_NOTIFICATIONS },
230+ NOTIFICATION_PERMISSION_REQUEST_CODE );
231+ } else {
232+ NotificationUtils .sendDirectReplyNotification (this );
233+ }
234+ } else if (itemId == MENU_TOGGLE_IME_FOCUSABLE_OVERLAY ) {
235+ if (!Settings .canDrawOverlays (this )) {
236+ Toast .makeText (this ,
237+ "Not allowed to show overlay.\n Check \" Settings > "
238+ + "Display over other apps\" " , Toast .LENGTH_LONG ).show ();
239+ } else {
240+ toggleOverlayView (true /* needsIme */ );
241+ item .setTitle (mShowOverlay ? getString (R .string .menu_show_ime_focusable_overlay )
242+ : getString (R .string .menu_hide_ime_focusable_overlay ));
243+ }
203244 }
204245 return true ;
205246 }
206247
248+ @ Override
249+ public void onRequestPermissionsResult (int requestCode , String [] permissions ,
250+ int [] grantResults ) {
251+ if (requestCode == NOTIFICATION_PERMISSION_REQUEST_CODE ) {
252+ if (grantResults .length == 1 &&
253+ grantResults [0 ] == PackageManager .PERMISSION_GRANTED ) {
254+ // Permission is granted. Continue to send the notification.
255+ NotificationUtils .sendDirectReplyNotification (this );
256+ } else {
257+ Log .d (TAG , "POST_NOTIFICATIONS Permissions denied." );
258+ Toast .makeText (this , "Required permission has denied" ,
259+ Toast .LENGTH_LONG ).show ();
260+ }
261+ }
262+ }
263+
264+ @ Override
265+ protected void onDestroy () {
266+ if (mOverlayTextView != null ) {
267+ getWindowManager ().removeView (mOverlayTextView );
268+ mOverlayTextView = null ;
269+ }
270+ }
271+
207272 @ Override
208273 public void onClick (final DialogInterface dialog , final int which ) {
209274 saveTheme (ThemeItem .THEME_LIST .get (which ));
@@ -476,4 +541,36 @@ private static String appendFlagText(final String text, final boolean flag, fina
476541 }
477542 return text ;
478543 }
544+
545+ private static boolean isNeedNotificationPermission () {
546+ for (Field field : Manifest .permission .class .getFields ()) {
547+ if (field .getName ().equals ("POST_NOTIFICATIONS" )) {
548+ Log .d (TAG , "Need notification permission." );
549+ return true ;
550+ }
551+ }
552+ return false ;
553+ }
554+
555+ private void toggleOverlayView (boolean needsIme ) {
556+ if (mOverlayTextView == null ) {
557+ Context overlayContext = createDisplayContext (getDisplay ())
558+ .createWindowContext (TYPE_APPLICATION_OVERLAY , null /* options */ );
559+ int focusableFlags = FLAG_NOT_FOCUSABLE | (needsIme ? FLAG_ALT_FOCUSABLE_IM : 0 );
560+ final WindowManager .LayoutParams params = new WindowManager .LayoutParams (
561+ TYPE_APPLICATION_OVERLAY , FLAG_WATCH_OUTSIDE_TOUCH | focusableFlags );
562+ final Rect windowBounds = getWindowManager ().getCurrentWindowMetrics ().getBounds ();
563+ params .width = windowBounds .width () / 3 ;
564+ params .height = windowBounds .height () / 3 ;
565+ params .gravity = TOP | LEFT ;
566+
567+ mOverlayTextView = new TextView (overlayContext );
568+ mOverlayTextView .setText ("I'm an IME focusable overlay" );
569+ mOverlayTextView .setBackgroundColor (BLUE );
570+ getWindowManager ().addView (mOverlayTextView , params );
571+ }
572+ mOverlayTextView .setVisibility (mShowOverlay ? View .VISIBLE : View .GONE );
573+ // Toggle the overlay visibility after the call.
574+ mShowOverlay = !mShowOverlay ;
575+ }
479576}
0 commit comments