blob: b9aaeabcd0835965c5c3aa20d857310c19c4ff38 [file] [log] [blame]
Jeff Browncf4db942010-09-03 10:19:28 -07001/*
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
17package com.example.android.apis.view;
18
19import com.example.android.apis.R;
20
21import android.app.Activity;
22import android.app.AlertDialog;
23import android.os.Bundle;
24import android.view.Gravity;
25import android.view.MotionEvent;
26import android.view.View;
27import android.view.View.OnClickListener;
28import android.view.View.OnTouchListener;
29import android.widget.Button;
30import 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 */
69public 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}