Merge "Protect autofill UI against redressing" into oc-dev

am: 0541862ec5

Change-Id: I0073d1eb75fc3460ad126ad08b9d4cf3f566a305
This commit is contained in:
Svetoslav Ganov
2017-06-09 21:25:58 +00:00
committed by android-build-merger
4 changed files with 86 additions and 14 deletions

View File

@@ -61,6 +61,8 @@ public final class AutoFillUI {
private final MetricsLogger mMetricsLogger = new MetricsLogger(); private final MetricsLogger mMetricsLogger = new MetricsLogger();
private final @NonNull OverlayControl mOverlayControl;
public interface AutoFillUiCallback { public interface AutoFillUiCallback {
void authenticate(int requestId, int datasetIndex, @NonNull IntentSender intent, void authenticate(int requestId, int datasetIndex, @NonNull IntentSender intent,
@Nullable Bundle extras); @Nullable Bundle extras);
@@ -75,6 +77,7 @@ public final class AutoFillUI {
public AutoFillUI(@NonNull Context context) { public AutoFillUI(@NonNull Context context) {
mContext = context; mContext = context;
mOverlayControl = new OverlayControl(context);
} }
public void setCallback(@NonNull AutoFillUiCallback callback) { public void setCallback(@NonNull AutoFillUiCallback callback) {
@@ -174,7 +177,7 @@ public final class AutoFillUI {
} }
hideAllUiThread(callback); hideAllUiThread(callback);
mFillUi = new FillUi(mContext, response, focusedId, mFillUi = new FillUi(mContext, response, focusedId,
filterText, new FillUi.Callback() { filterText, mOverlayControl, new FillUi.Callback() {
@Override @Override
public void onResponsePicked(FillResponse response) { public void onResponsePicked(FillResponse response) {
log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL); log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
@@ -255,7 +258,7 @@ public final class AutoFillUI {
} }
hideAllUiThread(callback); hideAllUiThread(callback);
mSaveUi = new SaveUi(mContext, providerLabel, info, mSaveUi = new SaveUi(mContext, providerLabel, info,
new SaveUi.OnSaveListener() { mOverlayControl, new SaveUi.OnSaveListener() {
@Override @Override
public void onSave() { public void onSave() {
log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);

View File

@@ -100,7 +100,7 @@ final class FillUi {
FillUi(@NonNull Context context, @NonNull FillResponse response, FillUi(@NonNull Context context, @NonNull FillResponse response,
@NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText, @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
@NonNull Callback callback) { @NonNull OverlayControl overlayControl, @NonNull Callback callback) {
mContext = context; mContext = context;
mCallback = callback; mCallback = callback;
@@ -146,7 +146,7 @@ final class FillUi {
mContentWidth = content.getMeasuredWidth(); mContentWidth = content.getMeasuredWidth();
mContentHeight = content.getMeasuredHeight(); mContentHeight = content.getMeasuredHeight();
mWindow = new AnchoredWindow(decor); mWindow = new AnchoredWindow(decor, overlayControl);
mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter); mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
} else { } else {
final int datasetCount = response.getDatasets().size(); final int datasetCount = response.getDatasets().size();
@@ -193,7 +193,7 @@ final class FillUi {
} }
applyNewFilterText(); applyNewFilterText();
mWindow = new AnchoredWindow(decor); mWindow = new AnchoredWindow(decor, overlayControl);
} }
} }
@@ -366,6 +366,7 @@ final class FillUi {
} }
final class AnchoredWindow implements View.OnTouchListener { final class AnchoredWindow implements View.OnTouchListener {
private final @NonNull OverlayControl mOverlayControl;
private final WindowManager mWm; private final WindowManager mWm;
private final View mContentView; private final View mContentView;
private boolean mShowing; private boolean mShowing;
@@ -375,9 +376,10 @@ final class FillUi {
* *
* @param contentView content of the window * @param contentView content of the window
*/ */
AnchoredWindow(View contentView) { AnchoredWindow(View contentView, @NonNull OverlayControl overlayControl) {
mWm = contentView.getContext().getSystemService(WindowManager.class); mWm = contentView.getContext().getSystemService(WindowManager.class);
mContentView = contentView; mContentView = contentView;
mOverlayControl = overlayControl;
} }
/** /**
@@ -391,6 +393,7 @@ final class FillUi {
.getString(R.string.autofill_picker_accessibility_title); .getString(R.string.autofill_picker_accessibility_title);
mWm.addView(mContentView, params); mWm.addView(mContentView, params);
mContentView.setOnTouchListener(this); mContentView.setOnTouchListener(this);
mOverlayControl.hideOverlays();
mShowing = true; mShowing = true;
} else { } else {
mWm.updateViewLayout(mContentView, params); mWm.updateViewLayout(mContentView, params);
@@ -423,6 +426,8 @@ final class FillUi {
// does, it should not crash the system. // does, it should not crash the system.
Slog.e(TAG, "Exception hiding window ", e); Slog.e(TAG, "Exception hiding window ", e);
mCallback.onDestroy(); mCallback.onDestroy();
} finally {
mOverlayControl.showOverlays();
} }
} }

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.autofill.ui;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
/**
* This class controls showing/hiding overlays. We don't
* hide all overlays (toast/system alerts) while sensitive
* autofill UI is up.
*/
class OverlayControl {
private final IBinder mToken = new Binder();
private final @NonNull AppOpsManager mAppOpsManager;
OverlayControl(@NonNull Context context) {
mAppOpsManager = context.getSystemService(AppOpsManager.class);
}
void hideOverlays() {
setOverlayAllowed(false);
}
void showOverlays() {
setOverlayAllowed(true);
}
private void setOverlayAllowed(boolean allowed) {
if (mAppOpsManager != null) {
mAppOpsManager.setUserRestriction(
AppOpsManager.OP_SYSTEM_ALERT_WINDOW, !allowed, mToken);
mAppOpsManager.setUserRestriction(
AppOpsManager.OP_TOAST_WINDOW, !allowed, mToken);
}
}
}

View File

@@ -99,14 +99,17 @@ final class SaveUi {
private final @NonNull OneTimeListener mListener; private final @NonNull OneTimeListener mListener;
private final @NonNull OverlayControl mOverlayControl;
private final CharSequence mTitle; private final CharSequence mTitle;
private final CharSequence mSubTitle; private final CharSequence mSubTitle;
private boolean mDestroyed; private boolean mDestroyed;
SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info, SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@NonNull OnSaveListener listener) { @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener) {
mListener = new OneTimeListener(listener); mListener = new OneTimeListener(listener);
mOverlayControl = overlayControl;
final LayoutInflater inflater = LayoutInflater.from(context); final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.autofill_save, null); final View view = inflater.inflate(R.layout.autofill_save, null);
@@ -197,16 +200,21 @@ final class SaveUi {
Slog.i(TAG, "Showing save dialog: " + mTitle); Slog.i(TAG, "Showing save dialog: " + mTitle);
mDialog.show(); mDialog.show();
mOverlayControl.hideOverlays();
} }
void destroy() { void destroy() {
if (sDebug) Slog.d(TAG, "destroy()"); try {
throwIfDestroyed(); if (sDebug) Slog.d(TAG, "destroy()");
mListener.onDestroy(); throwIfDestroyed();
mHandler.removeCallbacksAndMessages(mListener); mListener.onDestroy();
if (sVerbose) Slog.v(TAG, "destroy(): dismissing dialog"); mHandler.removeCallbacksAndMessages(mListener);
mDialog.dismiss(); if (sVerbose) Slog.v(TAG, "destroy(): dismissing dialog");
mDestroyed = true; mDialog.dismiss();
mDestroyed = true;
} finally {
mOverlayControl.showOverlays();
}
} }
private void throwIfDestroyed() { private void throwIfDestroyed() {