Merge "Protect autofill UI against redressing" into oc-dev
am: 0541862ec5
Change-Id: I07b91f8baa721b58f7f0ff9bf90a29481fdedaac
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,9 +200,11 @@ 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() {
|
||||||
|
try {
|
||||||
if (sDebug) Slog.d(TAG, "destroy()");
|
if (sDebug) Slog.d(TAG, "destroy()");
|
||||||
throwIfDestroyed();
|
throwIfDestroyed();
|
||||||
mListener.onDestroy();
|
mListener.onDestroy();
|
||||||
@@ -207,6 +212,9 @@ final class SaveUi {
|
|||||||
if (sVerbose) Slog.v(TAG, "destroy(): dismissing dialog");
|
if (sVerbose) Slog.v(TAG, "destroy(): dismissing dialog");
|
||||||
mDialog.dismiss();
|
mDialog.dismiss();
|
||||||
mDestroyed = true;
|
mDestroyed = true;
|
||||||
|
} finally {
|
||||||
|
mOverlayControl.showOverlays();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void throwIfDestroyed() {
|
private void throwIfDestroyed() {
|
||||||
|
|||||||
Reference in New Issue
Block a user