HIC: Add report facility for overzealous anti-falsing
Bug: 27405075
Change-Id: I15e5d601af3c7cc067371bbe51c873d2ce15ec83
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 2c8a559..3d70969 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -65,6 +65,14 @@
layout="@layout/keyguard_status_bar"
android:visibility="invisible" />
+ <Button
+ android:id="@+id/report_rejected_touch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
+ android:text="@string/report_rejected_touch"
+ android:visibility="gone" />
+
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
<include
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a0cb61a..36fa029 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1625,6 +1625,9 @@
<!-- Accessibility label for the notification icons in the collapsed status bar. Not shown on screen [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_notification_icon"><xliff:g name="app_name" example="Gmail">%1$s</xliff:g> notification: <xliff:g name="notification_text" example="5 new messages">%2$s</xliff:g></string>
+ <!-- Label for button that reports a touch that was wrongly rejected by the lockscreen. For debugging only. [CHAR LIMIT=NONE] -->
+ <string name="report_rejected_touch" translatable="false">Report rejected touch</string>
+
<!-- Multi-Window strings -->
<!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity and that things might crash/not work properly [CHAR LIMIT=NONE] -->
<string name="dock_forced_resizable">App may not work with split-screen.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 91f6520..b1f454e 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -21,6 +21,7 @@
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
@@ -28,6 +29,7 @@
import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
+import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
@@ -48,6 +50,8 @@
private static final String TAG = "DataCollector";
private static final String COLLECTOR_ENABLE = "data_collector_enable";
private static final String COLLECT_BAD_TOUCHES = "data_collector_collect_bad_touches";
+ private static final String ALLOW_REJECTED_TOUCH_REPORTS =
+ "data_collector_allow_rejected_touch_reports";
private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
public static final boolean DEBUG = false;
@@ -64,6 +68,7 @@
private boolean mCollectBadTouches = false;
private boolean mCornerSwiping = false;
private boolean mTrackingStarted = false;
+ private boolean mAllowReportRejectedTouch = false;
private static DataCollector sInstance = null;
@@ -87,6 +92,11 @@
mSettingsObserver,
UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(ALLOW_REJECTED_TOUCH_REPORTS), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
updateConfiguration();
}
@@ -104,10 +114,13 @@
mCollectBadTouches = mEnableCollector && 0 != Settings.Secure.getInt(
mContext.getContentResolver(),
COLLECT_BAD_TOUCHES, 0);
+ mAllowReportRejectedTouch = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ ALLOW_REJECTED_TOUCH_REPORTS, 0);
}
private boolean sessionEntrypoint() {
- if (mEnableCollector && mCurrentSession == null) {
+ if (isEnabled() && mCurrentSession == null) {
onSessionStart();
return true;
}
@@ -115,7 +128,7 @@
}
private void sessionExitpoint(int result) {
- if (mEnableCollector && mCurrentSession != null) {
+ if (mCurrentSession != null) {
onSessionEnd(result);
}
}
@@ -130,8 +143,36 @@
SensorLoggerSession session = mCurrentSession;
mCurrentSession = null;
- session.end(System.currentTimeMillis(), result);
- queueSession(session);
+ if (mEnableCollector) {
+ session.end(System.currentTimeMillis(), result);
+ queueSession(session);
+ }
+ }
+
+ public Uri reportRejectedTouch() {
+ if (mCurrentSession == null) {
+ Toast.makeText(mContext, "Generating rejected touch report failed: session timed out.",
+ Toast.LENGTH_LONG).show();
+ return null;
+ }
+ SensorLoggerSession currentSession = mCurrentSession;
+
+ currentSession.setType(Session.REJECTED_TOUCH_REPORT);
+ currentSession.end(System.currentTimeMillis(), Session.SUCCESS);
+ Session proto = currentSession.toProto();
+
+ byte[] b = Session.toByteArray(proto);
+ File dir = new File(mContext.getExternalCacheDir(), "rejected_touch_reports");
+ dir.mkdir();
+ File touch = new File(dir, "rejected_touch_report_" + System.currentTimeMillis());
+
+ try {
+ new FileOutputStream(touch).write(b);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return Uri.fromFile(touch);
}
private void queueSession(final SensorLoggerSession currentSession) {
@@ -164,7 +205,7 @@
@Override
public synchronized void onSensorChanged(SensorEvent event) {
- if (mEnableCollector && mCurrentSession != null) {
+ if (isEnabled() && mCurrentSession != null) {
mCurrentSession.addSensorEvent(event, System.nanoTime());
enforceTimeout();
}
@@ -186,7 +227,19 @@
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
+ /**
+ * @return true if data is being collected - either for data gathering or creating a
+ * rejected touch report.
+ */
public boolean isEnabled() {
+ return mEnableCollector || mAllowReportRejectedTouch;
+ }
+
+ /**
+ * @return true if the full data set for data gathering should be collected - including
+ * extensive sensor data, which is is not normally included with rejected touch reports.
+ */
+ public boolean isEnabledFull() {
return mEnableCollector;
}
@@ -401,8 +454,12 @@
}
private void addEvent(int eventType) {
- if (mEnableCollector && mCurrentSession != null) {
+ if (isEnabled() && mCurrentSession != null) {
mCurrentSession.addPhoneEvent(eventType, System.nanoTime());
}
}
+
+ public boolean isReportingEnabled() {
+ return mAllowReportRejectedTouch;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index faaad2b..b39803a 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -53,6 +53,10 @@
mType = Session.REAL;
}
+ public void setType(int type) {
+ mType = type;
+ }
+
public void end(long endTimestampMillis, int result) {
mResult = result;
mEndTimestampMillis = endTimestampMillis;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 1ac5992..664e886 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -22,6 +22,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.net.Uri;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
@@ -142,7 +143,7 @@
if (mHumanInteractionClassifier.isEnabled()) {
registerSensors(CLASSIFIER_SENSORS);
}
- if (mDataCollector.isEnabled()) {
+ if (mDataCollector.isEnabledFull()) {
registerSensors(COLLECTOR_SENSORS);
}
}
@@ -400,4 +401,15 @@
pw.print("mScreenOn="); pw.println(mScreenOn ? 1 : 0);
pw.println();
}
+
+ public Uri reportRejectedTouch() {
+ if (mDataCollector.isEnabled()) {
+ return mDataCollector.reportRejectedTouch();
+ }
+ return null;
+ }
+
+ public boolean isReportingEnabled() {
+ return mDataCollector.isReportingEnabled();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b623f19..1b0a05c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -73,6 +73,7 @@
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -85,6 +86,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
@@ -195,6 +197,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -365,6 +368,8 @@
private View mPendingRemoteInputView;
private View mPendingWorkRemoteInputView;
+ private View mReportRejectedTouch;
+
int mMaxAllowedKeyguardNotifications;
boolean mExpandedVisible;
@@ -929,6 +934,36 @@
mBatteryController);
mKeyguardStatusBar.setBatteryController(mBatteryController);
+ mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
+ if (mReportRejectedTouch != null) {
+ updateReportRejectedTouchVisibility();
+ mReportRejectedTouch.setOnClickListener(v -> {
+ Uri session = mFalsingManager.reportRejectedTouch();
+ if (session == null) { return; }
+
+ StringWriter message = new StringWriter();
+ message.write("Build info: ");
+ message.write(SystemProperties.get("ro.build.description"));
+ message.write("\nSerial number: ");
+ message.write(SystemProperties.get("ro.serialno"));
+ message.write("\n");
+
+ PrintWriter falsingPw = new PrintWriter(message);
+ FalsingLog.dump(falsingPw);
+ falsingPw.flush();
+
+ startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
+ .setType("*/*")
+ .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
+ .putExtra(Intent.EXTRA_STREAM, session)
+ .putExtra(Intent.EXTRA_TEXT, message.toString()),
+ "Share rejected touch report")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+ true /* onlyProvisioned */, true /* dismissShade */);
+ });
+ }
+
+
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mBroadcastReceiver.onReceive(mContext,
new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
@@ -2260,6 +2295,14 @@
Trace.endSection();
}
+ private void updateReportRejectedTouchVisibility() {
+ if (mReportRejectedTouch == null) {
+ return;
+ }
+ mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD
+ && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
+ }
+
protected int adjustDisableFlags(int state) {
if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
&& (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
@@ -4388,6 +4431,7 @@
mGroupManager.setStatusBarState(state);
mFalsingManager.setStatusBarState(state);
mStatusBarWindowManager.setStatusBarState(state);
+ updateReportRejectedTouchVisibility();
updateDozing();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
index afc8f77..50fd52a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
@@ -120,6 +120,7 @@
RESERVED_2 = 1;
RANDOM_WAKEUP = 2;
REAL = 3;
+ REJECTED_TOUCH_REPORT = 4;
}
optional uint64 startTimestampMillis = 1;