Home | History | Annotate | Download | only in view
      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
     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 
     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 
    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 
    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