1 /* 2 * Copyright (C) 2010 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.example.android.apis.view; 18 19 import com.example.android.apis.R; 20 21 import android.app.Activity; 22 import android.app.AlertDialog; 23 import android.os.Bundle; 24 import android.view.Gravity; 25 import android.view.MotionEvent; 26 import android.view.View; 27 import android.view.View.OnClickListener; 28 import android.view.View.OnTouchListener; 29 import android.widget.Button; 30 import android.widget.Toast; 31 32 33 /** 34 * This activity demonstrates two different ways in which views can be made more secure to 35 * touch spoofing attacks by leveraging framework features. 36 * 37 * The activity presents 3 buttons that obtensibly perform a risky security critical 38 * function. Under ordinary circumstances, the user would never click on these buttons 39 * or would at least think long and hard about it. However, a carefully crafted toast can 40 * overlay the contents of the activity in such a way as to make the user believe the buttons 41 * are innocuous. Since the toast cannot receive input, the touches are passed down to the 42 * activity potentially yielding an effect other than what the user intended. 43 * 44 * To simulate the spoofing risk, this activity pops up a specially crafted overlay as 45 * a toast layed out so as to cover the buttons and part of the descriptive text. 46 * For the purposes of this demonstration, pretend that the overlay was actually popped 47 * up by a malicious application published by the International Cabal of Evil Penguins. 48 * 49 * The 3 buttons are set up as follows: 50 * 51 * 1. The "unsecured button" does not apply any touch filtering of any kind. 52 * When the toast appears, this button remains clickable as usual which creates an 53 * opportunity for spoofing to occur. 54 * 55 * 2. The "built-in secured button" leverages the android:filterTouchesWhenObscured view 56 * attribute to ask the framework to filter out touches when the window is obscured. 57 * When the toast appears, the button does not receive the touch and appears to be inoperable. 58 * 59 * 3. The "custom secured button" adds a touch listener to the button which intercepts the 60 * touch event and checks whether the window is obscured. If so, it warns the user and 61 * drops the touch event. This example is intended to demonstrate how a view can 62 * perform its own filtering and provide additional feedback by examining the {@MotionEvent} 63 * flags to determine whether the window is obscured. Here we use a touch listener but 64 * a custom view subclass could perform the filtering by overriding 65 * {@link View#onFilterTouchEventForSecurity(MotionEvent)}. 66 * 67 * Refer to the comments on {@View} for more information about view security. 68 */ 69 public class SecureView extends Activity { 70 private int mClickCount; 71 72 @Override onCreate(Bundle savedInstanceState)73 protected void onCreate(Bundle savedInstanceState) { 74 super.onCreate(savedInstanceState); 75 76 setContentView(R.layout.secure_view); 77 78 Button toastButton = (Button) findViewById(R.id.secure_view_toast_button); 79 toastButton.setOnClickListener(new OnClickListener() { 80 public void onClick(View v) { 81 showOverlay(); 82 } 83 }); 84 85 Button unsecureButton = (Button) findViewById(R.id.secure_view_unsecure_button); 86 setClickedAction(unsecureButton); 87 88 Button builtinSecureButton = (Button) findViewById(R.id.secure_view_builtin_secure_button); 89 setClickedAction(builtinSecureButton); 90 91 Button customSecureButton = (Button) findViewById(R.id.secure_view_custom_secure_button); 92 setClickedAction(customSecureButton); 93 setTouchFilter(customSecureButton); 94 } 95 showOverlay()96 private void showOverlay() { 97 // Generate a toast view with a special layout that will position itself right 98 // on top of this view's interesting widgets. Sneaky huh? 99 SecureViewOverlay overlay = (SecureViewOverlay) 100 getLayoutInflater().inflate(R.layout.secure_view_overlay, null); 101 overlay.setActivityToSpoof(this); 102 103 Toast toast = new Toast(getApplicationContext()); 104 toast.setGravity(Gravity.FILL, 0, 0); 105 toast.setView(overlay); 106 toast.show(); 107 } 108 setClickedAction(Button button)109 private void setClickedAction(Button button) { 110 button.setOnClickListener(new OnClickListener() { 111 public void onClick(View v) { 112 String[] messages = getResources().getStringArray(R.array.secure_view_clicked); 113 String message = messages[mClickCount++ % messages.length]; 114 115 new AlertDialog.Builder(SecureView.this) 116 .setTitle(R.string.secure_view_action_dialog_title) 117 .setMessage(message) 118 .setNeutralButton(getResources().getString( 119 R.string.secure_view_action_dialog_dismiss), null) 120 .show(); 121 } 122 }); 123 } 124 setTouchFilter(Button button)125 private void setTouchFilter(Button button) { 126 button.setOnTouchListener(new OnTouchListener() { 127 public boolean onTouch(View v, MotionEvent event) { 128 if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 129 if (event.getAction() == MotionEvent.ACTION_UP) { 130 new AlertDialog.Builder(SecureView.this) 131 .setTitle(R.string.secure_view_caught_dialog_title) 132 .setMessage(R.string.secure_view_caught_dialog_message) 133 .setNeutralButton(getResources().getString( 134 R.string.secure_view_caught_dialog_dismiss), null) 135 .show(); 136 } 137 // Return true to prevent the button from processing the touch. 138 return true; 139 } 140 return false; 141 } 142 }); 143 } 144 } 145