Remove all non-platform code and clean up files.
Change-Id: I526498b4a545813a706f86a7a106d087d3d0cb57
diff --git a/PixelPerfect/Android.mk b/PixelPerfect/Android.mk
index 4c58f5b..c3cdea9 100644
--- a/PixelPerfect/Android.mk
+++ b/PixelPerfect/Android.mk
@@ -1,85 +1,7 @@
########
-# Step 1 : Build all protobufs in our tree into a separate
-# static java library. Useful for IDEs etc. since the generated
-# source folder can be excluded if required.
+# Step 1 : Build the platform app
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-proto-files-under, imported_protos/src)
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/imported_protos/src
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := libpixelperfect-protos
-LOCAL_SDK_VERSION := current
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-
-########
-# Step 2 : Build the shared platform library
-$(LOCAL_PATH) := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_MODULE := pixelperfect-api
-LOCAL_MODULE_TAG := optional
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src/com/google/android/apps/pixelperfect/api) \
- $(call all-Iaidl-files-under, src/com/google/android/apps/pixelperfect/api) \
- $(call all-java-files-under, src/com/google/android/apps/pixelperfect/util) \
- $(call all-proto-files-under, imported_protos/src)
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/imported_protos/src
-
-LOCAL_JAVA_LIBRARIES := guava
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-
-########
-# Step 3 : Build the main app
-
-$(LOCAL_PATH) := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Use Google certificate instead of platform certificate since GmsCore
-# only allows usage from apps signed with the Google certificate.
-LOCAL_CERTIFICATE := vendor/unbundled_google/libraries/certs/app
-
-platform_source_file_patterns = src/com/google/android/apps/pixelperfect/platform/%
-LOCAL_SRC_FILES := $(filter-out $(platform_source_file_patterns), $(call all-java-files-under, src))
-
-LOCAL_PACKAGE_NAME := PixelPerfect
-
-# Enable proguard.
-LOCAL_PROGUARD_ENABLED := full
-LOCAL_PROGUARD_FLAG_FILES := proguard.tests.flags
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-v13 \
- guava \
- pixelperfect-api \
- libpixelperfect-protos
-
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-# Include GMS Core's client library.
-# The exact version is controlled by res/values/version.xml
-include vendor/unbundled_google/packages/PrebuiltGmsCore/google-play-services-first-party.mk
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-# Step 4 : Build sub-packages (e.g. platform & tests)
-
-$(LOCAL_PATH) := $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
@@ -101,10 +23,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v13 \
guava \
- libpixelperfect-protos \
- pixelperfect-api
+ pixelperfect-api-prebuilt
-LOCAL_MANIFEST_FILE := platform/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := AndroidManifest.xml
+
# Include GMS Core's client library.
# The exact version is controlled by res/values/version.xml
include vendor/unbundled_google/packages/PrebuiltGmsCore/google-play-services-first-party.mk
@@ -116,7 +38,18 @@
include $(BUILD_PACKAGE)
########
-# Step 5 : Build sub-packages (e.g. platform & tests)
+# Step 2 : Build the prebuilt libraries
+
+$(LOCAL_PATH) := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ pixelperfect-api-prebuilt:libs/pixelperfect-api.jar
+
+include $(BUILD_MULTI_PREBUILT)
+
+########
+# Step 3 : Build sub-packages (e.g. tests)
# Use the following include to make our test apk.
include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/PixelPerfect/AndroidManifest.xml b/PixelPerfect/AndroidManifest.xml
index a555e1f..a4d957f 100644
--- a/PixelPerfect/AndroidManifest.xml
+++ b/PixelPerfect/AndroidManifest.xml
@@ -1,8 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.apps.pixelperfect"
+ package="com.google.android.apps.pixelperfect.platform"
android:versionCode="1"
android:versionName="1.0" >
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk
android:minSdkVersion="18"
@@ -10,30 +10,18 @@
<application
android:allowBackup="true"
android:icon="@drawable/ic_cat"
- android:label="@string/app_name" >
+ android:label="@string/platform_app_name" >
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<service
- android:name=".AccessibilityEventService"
- class=".AccessibilityEventService"
+ android:name=".PixelPerfectPlatform"
+ class=".PixelPerfectPlatform"
android:enabled="true"
- android:exported="false"
- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
+ android:exported="true" >
<intent-filter>
- <action android:name="android.accessibilityservice.AccessibilityService" />
+ <action android:name="com.google.android.apps.pixelperfect.api.IPixelPerfectPlatform" />
</intent-filter>
- <meta-data
- android:name="android.accessibilityservice"
- android:resource="@xml/accessibility_service_config" />
</service>
- <activity
- android:name="com.google.android.apps.pixelperfect.preferences.PreferencesActivity"
- android:screenOrientation="portrait" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
</application>
</manifest>
diff --git a/PixelPerfect/eclipse/gcore-fp.project b/PixelPerfect/eclipse/gcore-fp.project
deleted file mode 100644
index b49b722..0000000
--- a/PixelPerfect/eclipse/gcore-fp.project
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- mode: python; -*-
-
-name = 'gcore-fp'
-
-def CreateProperlyNamedLibLink(name):
- return Link(
- 'liblinks/%s.jar' % name,
- src='../../../out/target/common/obj/JAVA_LIBRARIES/'
- '%s_intermediates/javalib.jar' % name)
-
-files = [
- Link('res', src='../../../vendor/unbundled_google/packages/PrebuiltGmsCore/res'),
- Create('AndroidManifest.xml', contents='<manifest package="com.google.android.gms"/>\n'),
- Mkdir('libs'),
- CreateProperlyNamedLibLink('prebuilt-google-play-services-first-party'),
- Create('project.properties', contents='android.library=true\ntarget=android-19\n'),
- Mkdir('gen'),
-]
-
-classpath = [
- Src('gen'),
- Lib('liblinks/prebuilt-google-play-services-first-party.jar'),
- AndroidFramework(),
- Output('bin'),
-]
-
-project = AndroidProject(
- name=name,
- builders=[
- AndroidResourceManager(),
- AndroidPreCompiler(),
- JavaBuilder(),
- AndroidApkBuilder(),
- ]
-)
-
-formatting = 'eclipse/formatting.prefs'
-templates = 'eclipse/template.prefs'
diff --git a/PixelPerfect/eclipse/pixelperfect-test.project b/PixelPerfect/eclipse/pixelperfect-platform-test.project
similarity index 94%
rename from PixelPerfect/eclipse/pixelperfect-test.project
rename to PixelPerfect/eclipse/pixelperfect-platform-test.project
index 4393f5e..a136987 100644
--- a/PixelPerfect/eclipse/pixelperfect-test.project
+++ b/PixelPerfect/eclipse/pixelperfect-platform-test.project
@@ -1,6 +1,6 @@
# -*- mode: python; -*-
-name = 'pixelperfect-test'
+name = 'pixelperfect-platform-test'
def CreateProperlyNamedLibLink(name):
@@ -32,7 +32,7 @@
Src('gen'),
Lib('liblinks/junit4-target.jar', sourcepath='libsrcs/junit4-target'),
Lib('liblinks/mockito-api.jar', sourcepath='libsrcs/mockito-src'),
- Project('pixelperfect'),
+ Project('pixelperfect-platform'),
AndroidFramework(),
Output('bin'),
]
diff --git a/PixelPerfect/eclipse/pixelperfect.project b/PixelPerfect/eclipse/pixelperfect-platform.project
similarity index 83%
rename from PixelPerfect/eclipse/pixelperfect.project
rename to PixelPerfect/eclipse/pixelperfect-platform.project
index 044d2af..d2533a9 100644
--- a/PixelPerfect/eclipse/pixelperfect.project
+++ b/PixelPerfect/eclipse/pixelperfect-platform.project
@@ -1,6 +1,6 @@
# -*- mode: python; -*-
-name = 'pixelperfect'
+name = 'pixelperfect-platform'
def CreateProperlyNamedLibLink(name):
return Link(
@@ -14,17 +14,14 @@
Link('proguard.tests.flags'),
Link('res'),
Link('src'),
- Link('imported_protos'),
Link('scripts'),
Link('eclipse'),
- Link('platform'),
LinkFramework('framework-core', 'frameworks/base/core/java'),
LinkFramework('framework-java', 'libcore/luni/src/main/java'),
- CreateProperlyNamedLibLink('libpixelperfect-protos'),
+ CreateProperlyNamedLibLink('pixelperfect-api-prebuilt'),
CreateProperlyNamedLibLink('guava'),
CreateProperlyNamedLibLink('android-support-v13'),
CreateProperlyNamedLibLink('prebuilt-google-play-services-first-party'),
- Link('libsrcs/libpixelperfect-protos', src='../../../out/target/common/obj/JAVA_LIBRARIES/libpixelperfect-protos_intermediates/src/proto/src/'),
Link('libsrcs/android-support-v13', src='../../../frameworks/support/v13/java'),
Link('libsrcs/guava', src='../../../external/guava/guava/src/'),
Create('project.properties', contents='target=android-19\n'),
@@ -42,7 +39,7 @@
Src('gen'),
AndroidFrameworkSrc('framework-core'),
AndroidFrameworkSrc('framework-java'),
- Lib('liblinks/libpixelperfect-protos.jar', sourcepath='libsrcs/libpixelperfect-protos'),
+ Lib('liblinks/pixelperfect-api-prebuilt.jar'),
Lib('liblinks/guava.jar', sourcepath='libsrcs/guava'),
Lib('liblinks/android-support-v13.jar', sourcepath='libsrcs/android-support-v13'),
Lib('liblinks/prebuilt-google-play-services-first-party.jar'),
diff --git a/PixelPerfect/imported_protos/src/net/proto2/bridge/proto/message_set.proto b/PixelPerfect/imported_protos/src/net/proto2/bridge/proto/message_set.proto
deleted file mode 100644
index 6133df4..0000000
--- a/PixelPerfect/imported_protos/src/net/proto2/bridge/proto/message_set.proto
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2007 Google Inc. All rights reserved.
-// Author: kenton@google.com (Kenton Varda)
-//
-// This is proto2's version of MessageSet. See net/proto/message_set.h to
-// learn what MessageSets are and how they are used.
-//
-// In proto2, we implement MessageSet in terms of extensions, except with a
-// special wire format for backwards-compatibily. To define a message that
-// goes in a MessageSet in proto2, you must declare within that message's
-// scope an extension of MessageSet named "message_set_extension" and with
-// the field number matching the type ID. So, for example, this proto1 code:
-// message Foo {
-// enum TypeId { MESSAGE_TYPE_ID = 1234; }
-// }
-// becomes this proto2 code:
-// message Foo {
-// extend proto2.bridge.MessageSet {
-// optional Foo message_set_extension = 1234;
-// }
-// }
-//
-// Now you can use the usual proto2 extensions accessors to access this
-// message. For example, the proto1 code:
-// MessageSet mset;
-// Foo* foo = mset.get_mutable<Foo>();
-// becomes this proto2 code:
-// proto2::bridge::MessageSet mset;
-// Foo* foo = mset.MutableExtension(Foo::message_set_extension);
-//
-// Of course, new code that doesn't have backwards-compatibility requirements
-// should just use extensions themselves and not worry about MessageSet.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package proto2.bridge;
-
-option java_outer_classname = "MessageSetProtos";
-option java_multiple_files = true;
-
-message MessageSet {
- option message_set_wire_format = true;
- extensions 4 to max;
-}
diff --git a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/clientanalytics.proto b/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/clientanalytics.proto
deleted file mode 100644
index a40f702..0000000
--- a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/clientanalytics.proto
+++ /dev/null
@@ -1,353 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-// Author: neel@google.com (Neel Parekh)
-// jme@google.com (Big Tex Ellington)
-//
-// Protos by which Play clients communicate logging events to the Playlog
-// server. Do not update this file without understanding the implications --
-// e.g. android clients are built against Java generated from this proto.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package wireless_android_play_playlog;
-
-option java_package = "com.google.wireless.android.play.playlog.proto";
-option java_outer_classname = "ClientAnalytics";
-
-import "wireless/android/play/playlog/proto/play_games_client.proto";
-import "wireless/android/play/playlog/proto/play_store_client.proto";
-
-// Semi-arbitrary key-value pairs describing the event. Common entries
-// will be extracted into strongly typed fields in the GWS log records.
-message LogEventKeyValues {
- optional string key = 1;
- optional string value = 2;
-}
-
-// The set of currently active experiments for a given LogEvent.
-//
-// Next tag: 4
-message ActiveExperiments {
- // The list of IDs of client-behavior-altering experiments that are on.
- repeated string client_altering_experiment = 1;
-
- // The list of IDs of other experiments that are on. The client must not
- // change its hehavior in response to these experiments.
- repeated string other_experiment = 2;
-
- // The list of GWS experiments that are on. These are not targeted by Playlog.
- repeated int32 gws_experiment = 3;
-}
-
-// Next tag: 13
-message LogEvent {
- // Epoch time in milliseconds.
- optional int64 event_time_ms = 1;
-
- // Type of event, could be “CLICK” or “PAGE_VIEW” or “DOWNLOAD_STATUS”.
- // There will be a common repository of cross-vertical events that should be
- // used, but any individual app would be free to define their own tags.
- //
- // DISCOURAGED: use event_code instead.
- optional string tag = 2;
-
- // Type of event. Different kinds of events inside a client app should have
- // different values of 'event_code'. Different client apps may have
- // overlapping sets of 'event_code' values; these velues are only meant to
- // make sense within the context of a single client app, as identified by
- // the 'log_source' field of LogRequest.
- //
- // A typical way to use 'event_code' is to define the enum of possible values
- // inside of the clientevents/ subdirectory (example: http://cl/58990806).
- optional int32 event_code = 11;
-
- // Identifies a group of events that belong to the same flow or session of
- // user interaction, which is a client-specific concept.
- //
- // These IDs are used in the Clearcut/UMA pipeline for computing latencies
- // between pairs of events, where it is necessary to ensure that both events
- // belong to the same flow.
- //
- // For example, the Google Play team may want to give a unique ID to each
- // purchase session, including all of the events starting from the initial
- // search for an app to the eventual purchase and installation of the app.
- // Another example would be the Search app wanting to tie together search
- // query events and clicks on search results, especially if several instances
- // of the app may be active at the same time.
- optional int32 event_flow_id = 12;
-
- // Whether this event was initiated by the user at the time of the event or
- // shortly before (vs. a background event like upgrading a database after the
- // app was automatically updated).
- optional bool is_user_initiated = 10;
-
- // These might contain PII and will not be stored for more than 8 days.
- // If possible, please create a named field in the protos below instead.
- repeated LogEventKeyValues value = 3;
-
- // TODO: Deprecate/Remove. Use source_extension instead.
- //
- // Extension for Play Store app logs.
- optional PlayStoreLogEvent store = 4;
-
- // TODO: Deprecate/Remove. Use source_extension instead.
- //
- // Extension for Play Games app logs
- optional PlayGamesLogEvent games = 5;
-
- // First-party app usage tracking. Used only when log_source = APP_USAGE_1P.
- optional AppUsage1pLogEvent app_usage_1p = 9;
-
- // A source specific extension (typically a serialized proto). The type of
- // this data is determined by the log_source of the enclosing LogRequest.
- optional bytes source_extension = 6;
-
- // A JsProto version of source_extension, using array serialization format.
- optional bytes source_extension_js = 8;
-
- // The set of currently active experiments. If missing, then the server will
- // assume that experiment on/off status has not changed since the previous
- // LogEvent message in the same LogRequest proto. If missing in the very first
- // LogEveent of a LogRequest, then the server will assume that all experiments
- // are off.
- optional ActiveExperiments exp = 7;
-}
-
-// Atributes specific to Android clients.
-//
-// Next tag: 17
-message AndroidClientInfo {
- // "Gservices" android ID. Considered PII. Never logged in archival logs.
- optional int64 android_id = 1;
-
- // Pseudonymous, random id (sticky) per device. Never logged in temp logs.
- optional string logging_id = 2;
-
- // This comes from android.os.Build.VERSION.SDK_INT.
- optional int32 sdk_version = 3;
-
- // Textual description of the client platform. e.g., "Nexus 4".
- // This comes from android.os.Build.MODEL.
- optional string model = 4;
-
- // The name of the overall product. e.g., "occam".
- // This comes from android.os.Build.Product.
- optional string product = 5;
-
- // The name of the hardware (from the kernel command line or /proc).
- // This comes from android.os.Build.Hardware. e.g., "mako".
- optional string hardware = 8;
-
- // The name of the industrial design. e.g., "mako".
- // This comes from android.os.Build.Device.
- optional string device = 9;
-
- // This comes from android.os.Build.ID. e.g., something like "JRN54F".
- optional string os_build = 6;
-
- // The client application version. The java int version in the android package
- // converted to string.
- optional string application_build = 7;
-
- // The mobile country code / mobile network code (MCC/MNC).
- // e.g., 310004 for Verizon USA.
- optional string mcc_mnc = 10;
-
- // The chosen locale from the client. e.g., "en_US", "ko_KR", "en_GB".
- optional string locale = 11;
-
- // The chosen country from the client. e.g., "US", "KR", "JP".
- optional string country = 12;
-
- // The manufacturer of the hardware.
- // This comes from android.os.Build.MANUFACTURER
- optional string manufacturer = 13;
-
- // The brand the software is customized for, if any. Often a carrier name.
- // e.g. "google"
- // from http://developer.android.com/reference/android/os/Build.html#BRAND
- optional string brand = 14;
-
- // The name of the underlying board
- // e.g. "tuna"
- // from http://developer.android.com/reference/android/os/Build.html#BOARD
- optional string board = 15;
-
- // Radio version as reported by device, if available at reporting time
- // e.g. "I9250XXLJ1"
- // from http://developer.android.com/reference/android/os/Build.html#getRadioVersion()
- optional string radio_version = 16;
-}
-
-// Atributes specific to desktop clients.
-//
-// Next tag: 7
-message DesktopClientInfo {
- // Sticky ID that should be considered PII.
- optional string client_id = 1;
-
- // Pseudonymous, random id (sticky) per device. Never logged in temp logs.
- optional string logging_id = 2;
-
- // e.g., "mac", "windows", "linux"
- optional string os = 3;
-
- // e.g., "10.7", "Vista", "Win7"
- optional string os_major_version = 4;
-
- // e.g., "10.7.3", "Win7 SP1"
- optional string os_full_version = 5;
-
- // The client application version.
- optional string application_build = 6;
-}
-
-// Attributes specific to iOS clients.
-//
-// Next tag: 6
-message IosClientInfo {
- // Sticky ID that should be considered PII.
- optional string client_id = 1;
-
- // Pseudonymous, random id (sticky) per device. Never logged in temp logs.
- optional string logging_id = 2;
-
- optional string os_major_version = 3;
-
- optional string os_full_version = 4;
-
- // The client application version.
- optional string application_build = 5;
-}
-
-// Next tag: 5
-message ClientInfo {
- // The type of client that made this request.
- // Next enum tag: 5
- enum ClientType {
- UNKNOWN = 0;
- JS = 1;
- DESKTOP = 2;
- IOS = 3;
- ANDROID = 4;
- }
-
- optional ClientType client_type = 1 [default = UNKNOWN];
-
- // Only one of the following *_client_info fields will exist in any request.
- optional AndroidClientInfo android_client_info = 2;
- optional DesktopClientInfo desktop_client_info = 3;
- optional IosClientInfo ios_client_info = 4;
-}
-
-// The list of IDs of experiments that are currently on for this client. All
-// other experiments are off.
-//
-// Next tag: 2
-message ExperimentIdList {
- // IDs are sorted and do not contain duplicates.
- repeated string id = 1;
-}
-
-// First party app usage log event extension.
-// Used only when log_source = APP_USAGE_1P.
-//
-// Next tag: 19
-message AppUsage1pLogEvent {
- enum AppType {
- UNKNOWN = 0;
- GOOGLE_SEARCH = 1;
- GOOGLE_CALENDAR = 2;
- GOOGLE_PLUS = 3;
- GMAIL = 4;
- GOOGLE_PLAY_STORE = 5;
- GOOGLE_PLAY_MUSIC = 6;
- GOOGLE_PLAY_BOOKS = 7;
- GOOGLE_PLAY_VIDEO = 8;
- GOOGLE_PLAY_MAGAZINES = 9;
- GOOGLE_PLAY_GAMES = 10;
- GMS_CORE = 11;
- ANDROID_IDE = 12;
- ANDROID_TV = 13;
- LE = 14; // Location Engine within GMSCore, potentially with PII data
- GOOGLE_MAPS = 15;
- GOOGLE_CAMERA = 16;
- YOUTUBE = 17;
- ANDROID_TIMELY = 18;
- }
- optional AppType app_type = 1;
-
- // Package name of the app (on Android).
- optional string android_package_name = 2;
-
- // Version of the app.
- optional string version = 3;
-}
-
-// A LogRequest represents a batched collection of loggable events, each
-// event to be persited in a GWS log entry by the Playlog server.
-//
-// Next tag: 6
-message LogRequest {
- // Next enum tag: 28
- enum LogSource {
- UNKNOWN = -1;
-
- STORE = 0;
- MUSIC = 1;
- BOOKS = 2;
- VIDEO = 3;
- MAGAZINES = 4;
- GAMES = 5;
- LB_A = 6; // for collecting app usage stats (Lockbox project)
- ANDROID_IDE = 7; // Android IDE (go/android-diamond)
- LB_P = 8; // for collecting phone call events and stats (Lockbox project)
- LB_S = 9; // for collecting SMS events and stats (Lockbox project)
- GMS_CORE = 10; // Usage of GMS Core itself and its internal stats
- APP_USAGE_1P = 11; // First-party app usage tracking.
- ICING = 12; // Icing stats (AppDataSearch go/icing)
- HERREVAD = 13; // for collecting Nova Network quality data
- ANDROID_TV = 14; // Android TV, not Eureka.
- EDU_STORE = 15; // for collecting stats on Play for Education
- GMS_CORE_PEOPLE = 16; // GMS core people (aka menagerie)
- LE = 17; // Location Engine statistics
- GOOGLE_ANALYTICS = 18; // Google Analytics SDK health monitoring
- LB_D = 19; // for collecting device state changes (Lockbox project)
- ANDROID_GSA = 20; // Android GSA (Google Search App) stats
- LB_T = 21; // for collecting Android RunningTaskInfo (Lockbox project)
- PERSONAL_LOGGER = 22; // PixelPerfect activity logger
- GMS_CORE_WALLET_MERCHANT_ERROR = 23; // GMS core wallet merchant errors
- LB_C = 24; // Android contacts going from Now to Moonshine.
- ANDROID_AUTH = 25; // for collecting GMS core android auth data
- ANDROID_CAMERA = 26; // Android camera usage statistics
- CW = 27; // Clockwork interaction logs
- }
-
- // "Now", in milliseconds, according to the same clock that was used to set
- // 'event_time_ms' values in the LogEvent protos below.
- optional int64 request_time_ms = 4;
-
- optional ClientInfo client_info = 1;
- optional LogSource log_source = 2 [default = UNKNOWN];
- repeated LogEvent log_event = 3;
-
- // Can be used instead of 'log_event' in order to save battery in cases where
- // LogEvent protos are already serialized, and deserializing is undesirable.
- // If used, this is a collection of byte streams each produced using a
- // CodedOutputStream.
- repeated bytes serialized_log_events = 5;
-}
-
-// Next tag: 3
-message LogResponse {
- // Client should wait for next_request_wait_millis before sending the next log
- // request.
- optional int64 next_request_wait_millis = 1 [default = -1];
-
- // If present, this is the new set of enabled experiments for this client.
- // Otherwise, the client should assume that there has been no change in the
- // set of enabled experiments.
- optional ExperimentIdList experiments = 2;
-}
-
diff --git a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/personal_application_event.proto b/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/personal_application_event.proto
deleted file mode 100644
index a483af0..0000000
--- a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/personal_application_event.proto
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
-// Author: alasdair@google.com (Alasdair Mackintosh)
-//
-// A record of a user interaction event captured by PixelPerfect. Combines the
-// RecordedUpdate generated by the PersonalRecorder app with additional
-// information from the Clearcut log.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package wireless_android_play_playlog;
-
-import "net/proto2/bridge/proto/message_set.proto";
-import "wireless/android/play/playlog/proto/clientanalytics.proto";
-import "wireless/android/play/playlog/proto/personal_recorder.proto";
-
-option java_package = "com.google.wireless.android.play.playlog.proto";
-option java_outer_classname = "PersonalApplicationEventProto";
-
-message PersonalApplicationEvent {
- extend proto2.bridge.MessageSet {
- optional PersonalApplicationEvent message_set_extension = 58425595;
- }
-
- // Describes the client where this event came from
- optional ClientInfo client_info = 1;
-
- // The UTC timestamp for when this event happened.
- optional int64 timestamp_millis = 2;
-
- // The UTC timestamp that the client gave us for when this event happened.
- // Unreliable, but useful for diagnosing clock skew issues.
- optional int64 client_timestamp_millis = 3;
-
- // The event recorded by the client.
- optional RecordedUpdate recorded_update = 4;
-}
diff --git a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/personal_recorder.proto b/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/personal_recorder.proto
deleted file mode 100644
index 728fe69..0000000
--- a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/personal_recorder.proto
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
-// Author: alasdair@google.com (Alasdair Mackintosh)
-//
-// Interaction data captured by the PixelPerfect PersonalRecorder app. Records
-// how a user interacts with installed applications on their Android device.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-option java_package = "com.google.common.logging";
-option java_outer_classname = "RecordedEvent";
-
-package wireless_android_play_playlog;
-
-// The data contained in an android.graphics.Rect object
-message RecordedRect {
- optional int32 bottom = 1;
- optional int32 left = 2;
- optional int32 right = 3;
- optional int32 top = 4;
-}
-
-message RecordedTypes {
- // Represents the type of an Android screen widget.
- enum WidgetType {
- CUSTOM = 0; // Not a predefined Android type
- APP_WIDGET_HOST_VIEW = 1; // android.appwidget.AppWidgetHostView
- VIEW = 2; // android.view.View
- WEB_VIEW = 3; // android.webkit.WebView
- BUTTON = 4; // android.widget.Button
- CHECK_BOX = 5; // android.widget.CheckBox
- CHECKED_TEXT_VIEW = 6; // android.widget.CheckedTextView
- EDIT_TEXT = 7; // android.widget.EditText
- FRAME_LAYOUT = 8; // android.widget.FrameLayout
- HORIZONTAL_SCROLL_VIEW = 9; // android.widget.HorizontalScrollView
- IMAGE_BUTTON = 10; // android.widget.ImageButton
- IMAGE_VIEW = 11; // android.widget.ImageView
- LINEAR_LAYOUT = 12; // android.widget.LinearLayout
- LIST_VIEW = 13; // android.widget.ListView
- MULTI_AUTO_COMPLETE_TEXT_VIEW = 14; // android.widget.MultiAutoCompleteTextView
- PROGRESS_BAR = 15; // android.widget.ProgressBar
- RELATIVE_LAYOUT = 16; // android.widget.RelativeLayout
- SCROLL_VIEW = 17; // android.widget.ScrollView
- SPINNER = 18; // android.widget.Spinner
- SWITCH = 19; // android.widget.Switch
- TAB_HOST = 20; // android.widget.TabHost
- TAB_WIDGET = 21; // android.widget.TabWidget
- TEXT_VIEW = 22; // android.widget.TextView
- VIEW_SWITCHER = 23; // android.widget.ViewSwitcher
- }
-}
-
-// Represents an image, such as for screen shots.
-// Next available id: 6
-message Bitmap {
- // Possible bitmap configurations.
- // http://go/android-reference/android/graphics/Bitmap.Config.html
- // Next available id: 3
- message BitmapConfig {
- enum Config {
- UNKNOWN = 0;
- ALPHA_8 = 1;
- ARGB_4444 = 2;
- ARGB_8888 = 3;
- RGB_565 = 4;
- }
- // tag 1 is deprecated.
- optional Config value = 2;
- };
-
- // Known formats that the bitmap can be compressed to.
- // http://go/android-reference/android/graphics/Bitmap.CompressFormat.html
- // Next available id: 4
- message CompressionConfig {
- enum CompressFormat {
- UNKNOWN = 0;
- JPEG = 1;
- PNG = 2;
- WEBP = 3;
- }
- // tag 1 is deprecated.
- optional CompressFormat format = 2;
- optional int32 quality = 3;
- };
-
- // The actual bitmap.
- optional bytes bitmap = 1;
- optional int32 height = 2;
- optional int32 width = 3;
- // Bitmap and compression config.
- optional BitmapConfig bitmap_config = 4;
- optional CompressionConfig compression_config = 5;
-}
-
-message Screenshot {
- // Bitmap of the screenshot.
- optional Bitmap bitmap = 1;
- // Display rotation when screenshot was taken. We could "fix" the orientation
- // at the client, but it may be useful to preserve this information and let
- // any fixing, if required, be done by the analysis and processing machinery.
- // http://go/android-reference/android/view/Surface.html#ROTATION_0
- optional int32 rotation = 2;
-};
-
-// Represents an Android UI element, and optionally its children. Next
-// available id = 10
-message UIElement {
- // The type of the element. If the type is CUSTOM, the class_name will be set
- // to the full class name of the element's widget type. Otherwise the class
- // name will be empty. (We use this to avoid transmitting unnecessary string
- // data.)
- optional RecordedTypes.WidgetType class_type = 1 [default = CUSTOM];
-
- optional string class_name = 2;
-
- // The name of the Android UI resource. (The "android:id" property defined in
- // the app's layout XML file.)
- optional string resource_name = 3;
-
- // The android:contentDescription of this view item, if specified.
- optional string description = 4;
-
- // The text content of this item, if any.
- optional string content = 5;
-
- // Whether the content of the UIElement are intentionally elided.
- // This happens for sensitive fields, such as passwords.
- optional bool content_elided = 8 [default = false];
-
- // The boundary of this element, relative to its parent. See
- // http://developer.android.com/reference/android/view/accessibility/
- // AccessibilityNodeInfo.html#getBoundsInParent(android.graphics.Rect)
- optional RecordedRect rect = 6;
-
- // Screenshot for the corresponding UI element.
- // Screenshot is genuinely optional, and should not be assumed to be
- // present.
- optional Screenshot screenshot = 9;
-
- // Children of this element.
- repeated UIElement child = 7;
-}
-
-// Represents an update to the user's application, either caused by a direct
-// user action (pressing a button, entering text) or by the application
-// performing a screen update.
-message RecordedUpdate {
- // The type of the update. Corresponds to the types defined in
- // android.view.accessibility.AccessibilityEvent.
- enum Type {
- UNSET = 0;
- TYPE_NOTIFICATION_STATE_CHANGED = 1;
- TYPE_VIEW_CLICKED = 2;
- TYPE_VIEW_FOCUSED = 3;
- TYPE_VIEW_LONG_CLICKED = 4;
- TYPE_VIEW_SCROLLED = 5;
- TYPE_VIEW_SELECTED = 6;
- TYPE_VIEW_TEXT_CHANGED = 7;
- TYPE_VIEW_TEXT_SELECTION_CHANGED = 8;
- TYPE_WINDOW_CONTENT_CHANGED = 9;
- }
- optional Type type = 1;
-
- // The name of the package that triggered this event. Taken from the
- // getPackageName() method in android.view.accessibility.AccessibilityEvent.
- // E.g. "com.android.launcher" or "com.google.android.youtube".
- optional string package_name = 4;
-
- // The UIElement that this update applies to. If the type is
- // TYPE_WINDOW_CONTENT_CHANGED, then the element represents the root window,
- // and its children will be recursively populated. Otherwise it represents the
- // UI element where the event took place (e.g. the item that was clicked on)
- // and the children will not be populated.
- optional UIElement element = 2;
-
- // The version of the recorder application that published this udpate.
- optional string version = 3;
-}
diff --git a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/play_games_client.proto b/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/play_games_client.proto
deleted file mode 100644
index 7c71b27..0000000
--- a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/play_games_client.proto
+++ /dev/null
@@ -1,761 +0,0 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
-// Author: gshih@google.com (Grace Shih)
-//
-// Play Games logging protos. This is sent as a field within
-// clientanalytics.proto.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package wireless_android_play_playlog;
-
-option java_package = "com.google.wireless.android.play.playlog.proto";
-option java_outer_classname = "PlayGames";
-
-// DEPRECATED(11/07/2013): sent by old clients. Use GenericNotificationAction
-// Details about a user-visible notification sent from old clients
-message PlayGamesNotificationActionDeprecated {
-
- enum NotificationActionType {
-
- // The notification was received on the device.
- RECEIVED = 1;
-
- // The notification was displayed to the user.
- DISPLAYED = 2;
-
- // The user saw the notification and dismissed it.
- DISMISSED = 3;
-
- // The user interacted with the notification and opened it.
- OPENED = 4;
-
- // The system chose to revoke this notification without the user seeing it.
- // This could be because of action on another device, time limit, etc.
- CANCELED = 5;
-
- // This notification was consumed by another client before being displayed
- // to the user.
- CONSUMED = 6;
-
- // Next index: 7;
- }
-
- // The type of action this log event represents.
- optional NotificationActionType action_type = 1;
-
- // The IDs of the notifications this action is for, if any.
- repeated string notification_id = 2;
-
- // How many notifications are being displayed to the user.
- optional int32 displayed_count = 3;
-
- // Next index: 4;
-}
-
-// Details about the user-visible android notification
-message PlayGamesAndroidNotificationAction {
-
- enum NotificationActionType {
-
- // The notification type was unknown
- UNKNOWN = 0;
-
- // The notification was received on the device.
- RECEIVED = 1;
-
- // The notification was displayed to the user.
- DISPLAYED = 2;
-
- // The user saw the notification and dismissed it.
- DISMISSED = 3;
-
- // The user interacted with the notification and opened it.
- OPENED = 4;
-
- // The system chose to revoke this notification without the user seeing it.
- // This could be because of action on another device, time limit, etc.
- CANCELED = 5;
-
- // This notification was consumed by another client before being displayed
- // to the user.
- CONSUMED = 6;
-
- // Next index: 7;
- }
-
- // The type of action this log event represents.
- optional NotificationActionType action_type = 1;
-
- // The IDs of the notifications this action is for, if any.
- repeated string notification_id = 2;
-
- // How many notifications are being displayed to the user.
- optional int32 displayed_count = 3;
-
- // Next index: 4;
-}
-
-// Details about the iOS notification
-message PlayGamesIosNotificationAction {
-
- // The action the notification
- enum NotificationActionType {
-
- // The notification type was unknown
- UNKNOWN = 0;
-
- // The notification was received on the device.
- APP_CONSUMED = 1;
-
- // Next index: 2;
- }
-
- // The type of action this log event represents.
- optional NotificationActionType action_type = 1;
-
- // Next index: 2;
-}
-
-// Details about a user-visible notification
-message PlayGamesGenericNotificationAction {
-
- // The type of notification action this was
- enum NotificationPlatform {
- UNKNOWN = 0;
-
- // The notification was on an android device
- ANDROID = 1;
-
- // The notification was on an iOS device
- IOS = 2;
-
- // Next index: 3;
- }
-
- // Which type of notification this was
- optional NotificationPlatform action_type = 1;
-
- // Only one of the fields below will be populated
- // The Android notification details
- optional PlayGamesAndroidNotificationAction android_action = 2;
-
- // The iOS notification details
- optional PlayGamesIosNotificationAction ios_action = 3;
-
- // Next index: 4;
-}
-
-// Details about an iOS device registration
-message PlayGamesIosDeviceRegister {
-
- // 32 byte APNS device token assigned by apple.
- optional bytes apns_device_token = 1;
-
- // The iOS sdk version that sent the registration
- optional string sdk_version = 2;
-
- // The language of the device
- optional string language = 3;
-
- // Next index: 4
-}
-
-// Details about an iOS device unregistration
-message PlayGamesIosDeviceUnregister {
-
- // 32 byte APNS device token assigned by apple.
- optional bytes apns_device_token = 1;
-
- // Next index: 2
-}
-
-// Details about an iOS specific type of message
-message PlayGamesIosDeviceAction {
-
- // The type of iOS action
- enum IosDeviceActionType {
- UNKNOWN = 0;
-
- // The device token was registered
- REGISTER_DEVICE = 1;
-
- // The device token was unregistered
- UNREGISTER_DEVICE = 2;
-
- // Next index: 3
- }
-
- // What type of token registration was this and
- optional IosDeviceActionType action_type = 1;
-
- // Only one of these fields will be filled depending on action_type
- // The details of registration
- optional PlayGamesIosDeviceRegister register_action = 2;
-
- // The details of the unregistration
- optional PlayGamesIosDeviceUnregister unregister_action = 3;
-
- // Next index: 4;
-}
-
-// Details about the game tab in the destination app
-message PlayGamesDestinationAppGameTabInfo {
-
- // The application collection being viewed
- enum ApplicationCollection {
- UNKNOWN_COLLECTION = 0;
- FEATURED = 1;
- MULTIPLAYER = 2;
- PLAYED = 3;
- RECOMMENDED = 4;
- DOWNLOADED = 5;
- ALL_GAMES = 6;
- HIDDEN_GAMES = 7;
- INSTALLED = 8;
- // Next index = 9
- }
-
- // The collection type being displayed
- optional ApplicationCollection collection = 1;
-
- // True if user is viewing the top of the list, false if user has scrolled
- // down
- optional bool top_of_list = 2;
-
- // Tracking id for actions taken based on search / recommendations
- optional string discovery_tid = 3;
-
- // Next index: 4
-}
-
-// Details about a game purchase from the destination app
-message PlayGamesDestinationAppGamePurchase {
-
- // The price displayed to the user; null or 0 means free
- optional int64 price_micros = 1;
-
- // The purchase was successfully completed. (This only matters when
- // is_start_action = false.)
- optional bool has_completed_purchase = 2;
-
- // Tracking id for actions taken based on search / recommendations
- optional string discovery_tid = 3;
-
- // How far down in search / recommendations this game was displayed.
- optional uint32 ranking_position = 4;
-
- // Next index: 5
-}
-
-// Details about a game in the destination app
-message PlayGamesDestinationAppGameAction {
-
- // Which section the user is viewing on the game detail page
- enum GameDetailSection {
-
- // UNKNOWN
- UNKNOWN_SECTION = 0;
-
- // About game
- ABOUT = 1;
-
- // The achievements for the game
- ACHIEVEMENT_LIST = 2;
-
- // The leaderboards for the game
- LEADERBOARD_LIST = 3;
-
- // Friends who also play this game
- FRIEND_LIST = 4;
-
- // Next index: 5
- }
-
- // The app id of the game
- optional string application_id = 1;
-
- // The section the user is viewing
- optional GameDetailSection section = 2;
-
- // User launched the game from the dest app
- optional bool launched_game = 3;
-
- // Leaderboard actions if the player chose a specific leaderboard
- optional PlayGamesLeaderboardAction leaderboard = 4;
-
- // User clicked to purchase game from the dest app
- optional PlayGamesDestinationAppGamePurchase game_purchase = 5;
-
- // Tracking id for actions taken based on search / recommendations
- optional string discovery_tid = 6;
-
- // How far down in search / recommendations this game was displayed.
- optional uint32 ranking_position = 7;
-
- // Next index: 8
-}
-
-// Details about the game tab in the destination app
-message PlayGamesDestinationAppPlayerTabInfo {
-
- // The application collection being viewed
- enum PlayerCollection {
-
- // Unknown default actions
- UNKNOWN_COLLECTION = 0;
-
- // List of everyone in your circles
- ALL = 1;
-
- // List of people in your circles who have recently played games
- MOST_RECENT = 2;
-
- // List of people you may know
- YOU_MAY_KNOW = 3;
-
- // Next index: 4
- }
-
- // The collection type being displayed
- optional PlayerCollection collection = 1;
-
- // True if user is viewing the top of the list, false if user has scrolled
- // down
- optional bool top_of_list = 2;
-
- // Tracking id for actions taken based on search / recommendations
- optional string discovery_tid = 3;
-
- // Next index: 4
-}
-
-// Details about a player in the destination app
-message PlayGamesDestinationAppPlayerAction {
-
- // Which section the user is viewing on the player detail page
- enum PlayerDetailSection {
-
- // UNKNOWN
- UNKNOWN_SECTION = 0;
-
- // List of recently played games
- RECENTLY_PLAYED = 1;
-
- // Next index: 2
- }
-
- // The section the user is viewing
- optional PlayerDetailSection section = 1;
-
- // Tracking id for actions taken based on search / recommendations
- optional string discovery_tid = 2;
-
- // How far down in search / recommendations this game was displayed.
- optional uint32 ranking_position = 3;
-
- // Next index: 4
-}
-
-// Details about an action taken in the Settings page
-message PlayGamesDestinationAppSettingsAction {
-
- // True if the user switched accounts
- optional bool switched_account = 1;
-
- // True if the user enabled notifications, false if the user disabled
- // notifications
- optional bool mobile_notifications_enabled = 2;
-
- // True if the user enabled email notifications, false if the user
- // disabled email notifications
- optional bool email_notifications_enabled = 3;
-
- // True if the user enabled social sharing, false if the user
- // disabled social sharing
- optional bool social_sharing_enabled = 4;
-
- // The app id that the user chose to unmute notifications
- repeated string unmuted_notifications_app_id = 5;
-
- // Next index: 6
-}
-
-// Details about a destination app action
-message PlayGamesDestinationAppAction {
-
- // The page in the destination app that the user clicked on
- enum DestinationAppPageType {
-
- // Unknown page
- UNKNOWN_PAGE_TYPE = 0;
-
- // The splash screen
- SPLASH_SCREEN = 1;
-
- // The list of games
- GAME_TAB = 2;
-
- // The list of players/friends
- PLAYER_TAB = 3;
-
- // The list of matches
- MATCH_TAB = 4;
-
- // The detail page for a game
- GAME_DETAIL = 5;
-
- // The detail page for a player
- PLAYER_DETAIL = 6;
-
- // The settings page
- SETTINGS = 7;
-
- // Launched the play store
- PLAY_STORE = 8;
-
- // Next index: 9
- }
-
- // The page the user wants to view
- optional DestinationAppPageType page_type = 1;
-
- // Details about the game tab if page_type == GAMES_TAB
- optional PlayGamesDestinationAppGameTabInfo game_tab_info = 2;
-
- // Details about an action to a specific game
- optional PlayGamesDestinationAppGameAction game_action = 3;
-
- // Details about actions inside the settings page
- optional PlayGamesDestinationAppSettingsAction settings_action = 4;
-
- // Details about the player tab if page_type == PLAYER_TAB
- optional PlayGamesDestinationAppPlayerTabInfo player_tab_info = 5;
-
- // Details about an action to a specific player
- optional PlayGamesDestinationAppPlayerAction player_action = 6;
-
- // Next index: 7
-}
-
-// Details about a leaderboard list view, top scores, or score window action
-message PlayGamesLeaderboardAction {
-
- enum LeaderboardType {
-
- // Unknown leaderboard type
- UNKNOWN_LEADERBOARD_TYPE = 0;
-
- // Public leaderboard
- PUBLIC = 1;
-
- // Social leaderboard
- SOCIAL = 2;
-
- // Next index = 3;
- }
-
- enum ScoreWindowType {
-
- // Unknown score window type
- UNKNOWN_SCORE_WINDOW = 0;
-
- // The "daily" score window
- DAILY = 1;
-
- // The "weekly" score window
- WEEKLY = 2;
-
- // The "all time" score window
- ALL_TIME = 3;
-
- // Next index = 4;
- }
-
- // The leaderboard id this action is requesting
- optional string leaderboard_id = 1;
-
- // The type of the leaderboard
- optional LeaderboardType leaderboard_type = 2;
-
- // The score window type requested, if applicable
- optional ScoreWindowType score_window_type = 3;
-
- // Next index = 4;
-}
-
-// Details about a GPlus upgrade action
-message PlayGamesGPlusUpgrade {
-
- enum GPlusUpgradeStatus {
-
- // Unknown state
- UNKNOWN_GPLUS_UPGRADE = 0;
-
- // User accepted the G+ upgrade
- ACCEPT = 1;
-
- // User cancelled G+ upgrade
- CANCEL = 2;
-
- // Next index: 3
- }
-
- // Status of GPlus upgrade screen
- optional GPlusUpgradeStatus state = 1;
-
- // Next index: 2
-}
-
-// Details about the sign in account
-message PlayGamesSignInAccount {
-
- enum AccountStatus {
-
- // Unknown account status
- UNKNOWN_ACCOUNT_STATUS = 0;
-
- // User created a new account
- NEW = 1;
-
- // Proceeded passed the sign-in without account selector because user only
- // has one account
- PROCEED_NO_ACCOUNT_SELECTOR = 2;
-
- // Proceeded passed the sign-in with account selector because user has
- // multiple accounts
- PROCEED_WITH_ACCOUNT_SELECTOR = 3;
-
- // User canceled account sign-in
- CANCEL = 4;
-
- // Next index: 5
- }
-
- // The status of the account sign-in
- optional AccountStatus status = 1;
-
- // Next index: 2
-}
-
-// Details of an action taken inside a game
-message PlayGamesInGameAction {
-
- enum GameActionType {
-
- // Unknown action
- UNKNOWN_GAME_ACTION = 0;
-
- // User viewed the achievement list
- ACHIEVEMENT_LIST = 1;
-
- // User viewed the leaderboard list
- LEADERBOARD_LIST = 2;
-
- // User viewed a leaderboard top score
- LEADERBOARD_TOP_SCORES = 3;
-
- // User viewed a leaderboard score window
- LEADERBOARD_SCORE_WINDOW = 4;
-
- // User viewed game settings
- SETTINGS = 5;
-
- // User signed out of a game
- SIGN_OUT = 6;
-
- // User viewed the select opponents UI
- SELECT_OPPONENTS = 7;
-
- // User viewed the player search UI
- PLAYER_SEARCH = 8;
-
- // User viewed the waiting room UI
- WAITING_ROOM = 9;
-
- // User viewed the multiplayer inbox UI
- MULTIPLAYER_INBOX = 10;
-
- // User viewed the send request UI
- SEND_REQUEST = 11;
-
- // User viewed the request inbox UI
- REQUEST_INBOX = 12;
-
- // User viewed the public invitation list UI
- PUBLIC_INVITATION_LIST = 13;
-
- // User viewed the public request list UI
- PUBLIC_REQUEST_LIST = 14;
-
- // Next index: 15
- }
-
- // The action type
- optional GameActionType type = 1;
-
- // Leaderboard action, populated if one of the leaderboard game actions
- // were taken by the user
- optional PlayGamesLeaderboardAction leaderboard = 2;
-
- // Next index: 3
-}
-
-// Details of a sign-in action
-message PlayGamesSignInAction {
-
- enum SignInActionType {
-
- // Unknown action
- UNKNOWN_SIGN_IN_ACTION = 0;
-
- // Games service connection attempt
- // Sent whenever a game attempts to connect to the games service.
- CONNECTION_START = 1;
-
- // Sign in required
- // Sent when a game was sent the SIGN_IN_REQUIRED result.
- SIGN_IN_REQUIRED = 2;
-
- // Connection success
- // Sent when a game successfully connects to the games service.
- CONNECTION_SUCCESS = 3;
-
- // Next index: 4
- }
-
- // The account selector screen
- optional PlayGamesSignInAccount account = 1;
-
- // The G+ upgrade screen
- optional PlayGamesGPlusUpgrade gplus_upgrade = 2;
-
- // The type of action this event represents
- optional SignInActionType type = 3;
-
- // Next index: 4
-}
-
-// Details of a circle-modification action
-message PlayGamesModifyCirclesAction {
-
- enum CircleActionSource {
-
- // Unknown circle source
- UNKNOWN = 0;
-
- // Participant list
- PARTICIPANT_LIST = 1;
-
- // Recently played players
- RECENTLY_PLAYED_PLAYERS = 2;
-
- // Player search
- PLAYER_SEARCH = 3;
-
- // Player detail
- PLAYER_DETAIL = 4;
-
- // "You may know" list (player screen)
- YOU_MAY_KNOW_LIST_PLAYERS = 5;
-
- // "You may know" list (homescreen)
- YOU_MAY_KNOW_LIST_HOMESCREEN = 6;
-
- // Next index: 7
- }
-
- // The source of the modification action
- optional CircleActionSource source = 1;
-
- // Whether or not the player was added to circles
- optional bool added = 2;
-
- // Next index: 3
-}
-
-// Details about an Android sync action
-message PlayGamesAndroidSyncAction {
-
- // The authority the sync was requested for.
- optional string authority = 1;
-
- // Which feed, if any, triggered this sync operation.
- optional string feed = 2;
-
- // The duration of the sync operation in milliseconds.
- optional int64 duration_millis = 3;
-
- // Whether or not this sync completed successfully.
- optional bool success = 4;
-
- // How many errors were encountered during this sync operations. Note that
- // this may be 0 and still have the success flag set to false if the sync
- // generated a non-recoverable error.
- optional int32 num_errors = 5;
-
- // Next index: 6
-}
-
-// Details about the request
-message PlayGamesRequestInfo {
-
- // True if the action indicates the start of the request, false if the action
- // indicates the end of the request. This field is necessary only when we
- // care about the latency of this action. In order to accurately calculate
- // latency, also include the start_timestamp_millis field below.
- optional bool is_start_action = 1;
-
- // The 3P application id making the request
- optional string application_id = 2;
-
- // The start timestamp that should be logged if we care about latency of this
- // action. Should only be logged if is_start_action = false. This should
- // correspond to the PlaylogLogProto timestamp_millis field so that we can
- // later Dremel the start and stop log events.
- optional int64 start_timestamp_millis = 3;
-
- // The instance ID of the application making the request. On Android, this
- // will be a package name. On iOS, this will be the bundle identifier.
- optional string instance_id = 4;
-
- // Version of the client SDK that sent this request.
- optional string client_version = 5;
-
- // Next index: 6;
-}
-
-// A Play Games log event
-message PlayGamesLogEvent {
-
- // General info about the request. Every action should log this field.
- optional PlayGamesRequestInfo request_info = 1;
-
- // A user sign-in action
- optional PlayGamesSignInAction sign_in = 2;
-
- // An action that occurs within a game
- optional PlayGamesInGameAction in_game = 3;
-
- // An action that occurs within the games destination app
- optional PlayGamesDestinationAppAction dest_app = 4;
-
- // DEPRECATED(11/07/2013): action only sent by old clients. Instead use
- // generic_notification.
- optional PlayGamesNotificationActionDeprecated notification = 5;
-
- // Notification action used by all clients
- optional PlayGamesGenericNotificationAction generic_notification = 6;
-
- // An iOS device registration/unregistration action
- optional PlayGamesIosDeviceAction ios_action = 7;
-
- // Action logged when modifying the state of the user's circles
- optional PlayGamesModifyCirclesAction modify_circles = 8;
-
- // Action logged when a device performs a sync
- optional PlayGamesAndroidSyncAction sync = 9;
-
- // Next index: 10
-}
diff --git a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/play_store_client.proto b/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/play_store_client.proto
deleted file mode 100644
index 0942cef..0000000
--- a/PixelPerfect/imported_protos/src/wireless/android/play/playlog/proto/play_store_client.proto
+++ /dev/null
@@ -1,1171 +0,0 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
-// Authors: abednego@google.com (Igor Naverniouk)
-// aurash@google.com (Aurash Mahbod)
-// stadler@google.com (Andy Stadler)
-// chstuder@google.com (Christoph Studer)
-//
-// Play Store logging protos. This is sent as a field within
-// clientanalytics.proto.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package wireless_android_play_playlog;
-
-option java_package = "com.google.wireless.android.play.playlog.proto";
-option java_outer_classname = "PlayStore";
-
-// Client-generated information that accompanies a PlayStoreUiElement.
-message PlayStoreUiElementInfo {
- // For payment instrument related UI elements.
- optional InstrumentInfo instrument_info = 1;
-
- message InstrumentInfo {
- // The instrument family as defined in InstrumentEnums.Family:
- // wireless/android/finsky/proto/billing/device/common.proto
- optional int32 instrument_family = 1;
-
- // True if the payment instrument is marked as the default.
- optional bool is_default = 2;
- }
-
- // Serialized finsky.Docid(e.g. "["MUSIC",2,2]"), for web front end only,
- // that is associated with the node such as Page, DocList, or Document.
- // This field is deprecated. Instead set the docid in server_logs_cookie.
- optional string serial_docid = 2;
-
- // Host name of server used for a WebViewChallenge. Never the full URL.
- optional string host = 3;
-
- // The encoded docid for document specific UI elements that don't contain a
- // server logs cookie. Only use this if it's impossible to use a server logs
- // cookie.
- //
- // E.g. "inapp:potion:com.android.vending" or "book-012345678901".
- //
- // See java/com/google/wireless/android/finsky/util/DocidUtils.java for the
- // encoding / decoding functions.
- optional string document = 4;
-
- // The Offer.Type for purchase related UI elements that don't contain a
- // server logs cookie. Only use this if it's impossible to use a server logs
- // cookie.
- //
- // Offer.Type defined here: wireless/android/finsky/proto/common.proto
- optional int32 offer_type = 5;
-}
-
-// Something that can be displayed on a page and possibly clicked.
-// A DOM node, essentially, for interesting nodes.
-message PlayStoreUiElement {
-
- // If you add a Type value, and you want elements of that type to be tracked
- // as "clusters" in the playstats anaylitics pipeline, you *must* add
- // [(is_cluster) = true] to the enum value definition.
- // Next range available beyond: 1250
- enum Type {
- OTHER = 0;
-
- // Top-level pages.
- BROWSE_PAGE = 1;
- DETAILS_PAGE = 2;
- SEARCH_PAGE = 3;
- // For someone else's people page
- PEOPLE_PAGE= 4;
- WISHLIST_PAGE = 5;
- ANTENNA_PAGE = 6;
- CREATOR_DETAILS_PAGE = 7;
- FREE_SONG_OF_THE_DAY_PAGE = 8;
- MY_APPS_PAGE = 9;
- // For your own people page
- MY_PEOPLE_PAGE = 10;
- // Tag 11 available
- SETTINGS_PAGE = 12;
- AVAILABLE_PROMO_OFFER_ACTIVITY = 13;
-
- // Links
- CATEGORY_LINK = 100; // Category links.
- QUICK_LINK = 101; // Links to other pages.
- SEARCH_LINK = 102;
- MY_APPS_LINK = 103;
- MY_MUSIC_LINK = 104;
- MY_MOVIES_AND_TV_LINK = 105;
- MY_BOOKS_LINK = 106;
- MY_MAGAZINES_LINK = 107;
- MY_WISHLIST_LINK = 108;
- REDEEM_LINK = 109;
- ACCOUNTS_LINK = 110;
- SETTINGS_LINK = 111;
- HELP_LINK = 112;
- BADGE_LINK = 113;
- VISIT_DEV_SITE_LINK = 114;
- SEND_DEV_EMAIL_LINK = 115;
- DEVELOPER_PRIVACY_LINK = 116;
- ARTIST_LINK = 117;
- ARTIST_YOUTUBE_LINK = 118;
- ARTIST_GOOGLEPLUS_LINK = 119;
- PLAY_YOUTUBE_LINK = 120;
- MY_NEWSSTAND_LINK = 121;
- MY_MOVIES_LINK = 122;
- MY_PEOPLE_PAGE_LINK = 123;
-
- // Common UI elements.
-
- PRICE_BUTTON = 200;
- ACCEPT_AND_BUY_BUTTON = 201;
- SHARE_BUTTON = 202;
- // Button that takes you to the wishlist
- WISHLIST_BUTTON = 203;
- // Add an item to the wishlist
- WISHLIST_ADD_ITEM_BUTTON = 204;
- // Remove an item from the wishlist
- WISHLIST_REMOVE_ITEM_BUTTON = 205;
- // No longer sent from device starting from MintJulep.
- // See tags 1200+ instead.
- RATE_AND_REVIEW_BUTTON = 206;
- FLAG_INAPPROPRIATE_BUTTON = 207;
- PLUS_ONE_BUTTON = 208;
- DETAILS_DOCUMENT = 209;
- AUTO_UPDATE_STATE_BUTTON = 210;
- SEASON_SELECTOR = 211;
- // Dismiss a document (e.g. bad recommendation)
- DISMISS_ITEM_BUTTON = 212;
- LOADING_SPINNER = 213;
- REFUND_BUTTON = 214;
- UNINSTALL_BUTTON = 215;
- DEACTIVATE_BUTTON = 216;
- UPDATE_BUTTON = 217;
- // This is any "open document" button, text is corpus-specific
- // and may be "Open", "Play", "Listen", "Read", etc.
- LAUNCH_BUTTON = 218;
- CONTINUE_LAUNCH_BUTTON = 219;
- ENABLE_BUTTON = 220;
- INSTALL_BUTTON = 221;
- TRY_BUTTON = 222;
- FREE_BUTTON = 223;
- DOWNLOAD_BUTTON = 224;
- OPEN_FREE_BOOK_BUTTON = 225;
- SUBSCRIBE_PRICE_BUTTON = 226;
- UNSUBSCRIBE_BUTTON = 227;
- RENT_SD_BUTTON = 228;
- RENT_HD_BUTTON = 229;
- RENT_FROM_BUTTON = 230;
- BUY_SD_BUTTON = 231;
- BUY_HD_BUTTON = 232;
- BUY_FROM_BUTTON = 233;
- PREORDER_BUTTON = 234;
- PREORDER_CANCEL_BUTTON = 235;
- // Used on the auto-update cleanup dialog when the user does not want
- // to have their settings changed.
- AUTO_UPDATE_CLEANUP_NOT_YET_BUTTON = 236;
- // Used on the auto-update cleanup dialog when the user agrees to have
- // all of their apps auto-updated.
- AUTO_UPDATE_CLEANUP_OK_BUTTON = 237;
- // A button that brings up an overflow menu (on a card)
- OVERFLOW_MENU_BUTTON = 238;
- // Buttons on details page.
- INFO_BUTTON = 239;
- SCREENSHOTS_BUTTON = 240;
- TRAILER_BUTTON = 241;
- // A specific active subscription, shown on a details page
- ACTIVE_SUBSCRIPTION = 242;
- // Confirm canceling a subscription
- CANCEL_SUBSCRIPTION_YES = 243;
- // Don't confirm canceling a subscription
- CANCEL_SUBSCRIPTION_NO = 244;
- // Confirm canceling a preorder
- CANCEL_PREORDER_YES = 245;
- // Don't confirm canceling a preorder
- CANCEL_PREORDER_NO = 246;
- // Clicked "continue" in GAIA recovery offer dialog
- GAIA_RECOVERY_YES = 247;
- // Exited GAIA recovery offer dialog
- GAIA_RECOVERY_NO = 248;
- // Container Filter selector (e.g. "For Tablets" / "All Apps")
- CONTAINER_FILTER_SELECTOR = 249;
- // OTA install dialog cancel / "No thanks" button
- OTA_INSTALL_DIALOG_CANCEL_BUTTON = 250;
- // OTA install dialog "Install" button
- OTA_INSTALL_DIALOG_INSTALL_BUTTON = 251;
- // Available promo offer
- AVAILABLE_PROMO_OFFER_CHOSE = 252;
- AVAILABLE_PROMO_OFFER_SKIP = 253;
- // OK/Cancel buttons on Content Filter
- CONTENT_FILTER_YES = 254;
- CONTENT_FILTER_NO = 255;
- // Details translation toggle
- DETAILS_TRANSLATE_YES = 256;
- DETAILS_TRANSLATE_NO = 257;
- // PIN entry dialog
- PIN_ENTRY_YES = 258;
- PIN_ENTRY_NO = 259;
- // 260-264 no longer sent from device starting with MintJulep. See tags
- // 1200+ instead
- RATE_REVIEW_YES = 260;
- RATE_REVIEW_NO = 261;
- RATE_REVIEW_CONFIRM_GPLUS_SIGNUP = 262;
- RATE_REVIEW_CONFIRM_GPLUS_ACCEPTED = 263;
- RATE_REVIEW_CONFIRM_GPLUS_NO = 264;
- // Gaia authentication - succeed, fail, cancel
- GAIA_AUTHENTICATION_YES = 265;
- GAIA_AUTHENTICATION_NO = 266;
- // WebView Challenge - succeed or fail. If a URL was clicked
- // (typically containing the target pattern or the cancel pattern)
- // then the host name part of the URL will be logged in the
- // client cookie.
- WEBVIEW_CHALLENGE_YES = 267;
- WEBVIEW_CHALLENGE_NO = 268;
- // Confirm Archive Docs dialog - OK or cancel
- ARCHIVE_DOCS_YES = 269;
- ARCHIVE_DOCS_NO = 270;
- // Episode expansion toggle
- EPISODE_EXPANSION_YES = 271;
- EPISODE_EXPANSION_NO = 272;
- SHARE_GPLUS = 273;
- // Used when the user accepts the suggestion to install Play Games.
- PLAY_GAMES_SUGGESTION_INSTALL_BUTTON = 274;
- // Used when the user declines the suggestion to install Play Games.
- PLAY_GAMES_SUGGESTION_NOT_NOW_BUTTON = 275;
- UPDATE_ALL_BUTTON = 276;
- // The user has switched the side drawer to display destinations
- DRAWER_SWITCH_TO_DESTINATIONS = 277;
- // The user has switched the side drawer to display accounts
- DRAWER_SWITCH_TO_ACCOUNTS = 278;
- // A clickable person avatar that leads that to that person's people page.
- PERSON_AVATAR = 279;
- // A circles button that invokes the circle picker.
- CIRCLES_BUTTON = 280;
- // A button that leads to a person's G+ profile in the G+ app
- VIEW_GPLUS_PROFILE_BUTTON = 281;
- // A slightly-hidden "self update" button
- SELF_UPDATE_BUTTON = 282;
-
- // Dialogs and overlays.
- PASSWORD_PROMPT_DIALOG = 300;
- FLAG_ITEM_DIALOG = 301;
- // Refers to the dialog that shows more reviews of a doc
- REVIEWS_DIALOG = 302;
- WARM_WELCOME_DIALOG = 303;
- CANCEL_SUBSCRIPTION_DIALOG = 304;
- CANCEL_PREORDER_DIALOG = 305;
- AUTO_UPDATE_CLEANUP_DIALOG = 306;
- GAIA_RECOVERY_DIALOG = 307;
- // This dialog is shown when a limited user is blocked from client
- ACCESS_RESTRICTED_DIALOG = 308;
- OTA_INSTALL_DIALOG = 309;
- CHOOSE_ACCOUNT_DIALOG = 310;
- PIN_ENTRY_DIALOG = 311;
- // 312-313 no longer sent from client starting in Mintjulep. See tags 1200+
- // instead.
- RATE_REVIEW_DIALOG = 312;
- RATE_REVIEW_CONFIRM_GPLUS_DIALOG = 313;
- GAIA_AUTHENTICATION_DIALOG = 314;
- CONTENT_FILTER_DIALOG = 315;
- WEBVIEW_CHALLENGE = 316;
- ARCHIVE_DOCS_DIALOG = 317;
- // This dialog is shown to suggest that the user install Play Games.
- PLAY_GAMES_SUGGESTION_DIALOG = 318;
- // Dialog that shows the list of people that +1'ed a doc
- PLUS_ONE_DIALOG = 319;
-
- // Cluster types
- // The generic cluster UI element that has child documents. Cluster
- // elements will be accompanied by a DOC_LIST server logs cookie.
- // TODO: add enum values to classify all visual cluster types we are
- // interested in.
- UNCLASSIFIED_CLUSTER = 400;
- // A tab containing categories. Probably won't have a server cookie.
- CATEGORIES_TAB = 401;
- // A tab containing promo displays.
- PROMO_TAB = 402;
- // A tab containing regular contents.
- CONTENTS_TAB = 403;
- // A tab containg subscriptions (My Apps)
- MY_APPS_SUBSCRIPTIONS_TAB = 404;
- // A tab containing installed apps (My Apps)
- MY_APPS_INSTALLED_TAB = 405;
- // A tab containing library apps (My Apps)
- MY_APPS_LIBRARY_TAB = 406;
- // A merchandising cluster
- MERCHANDISING_CLUSTER = 407;
- // A generic type for the list response for a given tab. This will be
- // the only child node under a PROMO_TAB or a CONTENTS_TAB.
- DFE_LIST_TAB = 408;
- // A cluster that is represented as a merchandized banner.
- MERCH_BANNER_CLUSTER = 409;
- // A cluster of people you may know to add to your circles
- SUGGESTED_PEOPLE_CLUSTER = 410;
- // A cluster for a trusted source that you can follow
- TRUSTED_SOURCE_CLUSTER = 411;
- // A cluster that allows the user to rate multiple items
- MULTI_RATE_CLUSTER = 412;
- // A cluster that provides suggestions after rating a items
- RATE_AND_QUICK_SUGGESTION_CLUSTER = 413;
-
- // Card types
- // The generic card UI element (applies to all cards shown on the screen).
- // Card elements will be accompanied by a DOCUMENT server logs cookie.
- // #500 is deprecated, please use a specific CARD_VIEW_ type (See below)
- UNCLASSIFIED_CARD = 500;
- // An app displayed in a list in MyApps
- MY_APPS_LIST_CARD = 501;
- // A song displayed in a list of songs
- SONG_SNIPPET_CARD = 502;
- // An episode displayed in a list of episodes
- EPISODE_SNIPPET_CARD = 503;
- // Variations on the "play card" size/shape
- CARD_VIEW_ARTIST = 504;
- CARD_VIEW_LARGE = 505;
- CARD_VIEW_LISTING_SMALL = 506;
- CARD_VIEW_MEDIUM = 507;
- CARD_VIEW_MEDIUM_PLUS = 508;
- CARD_VIEW_MINI = 509;
- CARD_VIEW_SINGLE = 510;
- CARD_VIEW_SMALL = 511;
- CARD_VIEW_EDITORIAL_APP = 512;
- CARD_VIEW_EDITORIAL_NON_APP = 513;
- // Card that allows for the rating of an item
- CARD_VIEW_RATE = 514;
- // Card displaying a person and allows for the adding of that person
- CARD_VIEW_PERSON = 515;
-
- // System UI elements
- SYSTEM_BACK_BUTTON = 600;
- SYSTEM_TAP_OUTSIDE = 601;
- SYSTEM_UP_BUTTON = 602;
- // Indicates that the parent UI element (typically a dialog, screen, or
- // activity) has been closed, caused by a user action or automatically.
- SYSTEM_CLOSED = 603;
-
- // Purchasing 700 - 899
-
- // Purchase dialog
- PURCHASE_DIALOG = 700;
- PURCHASE_CART_SCREEN = 710;
- PURCHASE_CART_BUY_BUTTON = 711;
- PURCHASE_CART_CONTINUE_BUTTON = 712;
- PURCHASE_CART_EXPANSION_TOGGLE = 713;
- PURCHASE_CART_PAYMENT_OPTIONS_LINK = 714;
- PURCHASE_CART_EXPANDED_DETAILS = 715;
- PURCHASE_AUTH_SCREEN = 750;
- PURCHASE_AUTH_CONFIRM_BUTTON = 751;
- PURCHASE_AUTH_HELP_TOGGLE = 752;
- PURCHASE_AUTH_OPT_OUT_CHECKBOX = 753;
- PURCHASE_ERROR_SCREEN = 770;
- PURCHASE_ERROR_OK_BUTTON = 771;
- PURCHASE_SUCCESS_SCREEN = 775;
-
- // Disambiguation
- PURCHASE_DISAMBIGUATION_DIALOG = 780;
- PURCHASE_DISAMBIGUATION_SCREEN = 781;
- PURCHASE_DISAMBIGUATION_ENTRY = 782;
-
- // Apps permissions
- PURCHASE_APPS_PERMISSIONS_DIALOG = 790;
- PURCHASE_APPS_PERMISSIONS_SCREEN = 791;
- PURCHASE_APPS_PERMISSIONS_ACCEPT_BUTTON = 792;
-
- // Billing profile / instrument switching
- PURCHASE_PROFILE_DIALOG = 800;
- PURCHASE_PROFILE_SCREEN = 801;
- PURCHASE_PROFILE_EXISTING_INSTRUMENT = 802;
- PURCHASE_PROFILE_ACTION_ADD_CREDIT_CARD = 810;
- PURCHASE_PROFILE_ACTION_ADD_CARRIER_BILLING = 811;
- PURCHASE_PROFILE_ACTION_REDEEM_CODE = 812;
- PURCHASE_PROFILE_ACTION_TOP_UP = 813;
-
- // DCB purchase flow
- PURCHASE_DCB_PASSWORD_DIALOG = 820;
- PURCHASE_DCB_PASSWORD_DIALOG_OK_BUTTON = 821;
- PURCHASE_DCB_PASSWORD_DIALOG_CANCEL_BUTTON = 822;
- PURCHASE_DCB_TOS_DIALOG = 823;
- PURCHASE_DCB_TOS_DIALOG_ACCEPT_BUTTON = 824;
- PURCHASE_DCB_TOS_DIALOG_DECLINE_BUTTON = 825;
-
- // Setup DCB
- PURCHASE_DCB2_SETUP_DIALOG = 840;
- PURCHASE_DCB3_SETUP_DIALOG = 841;
- // Dialog shown while performing account association.
- PURCHASE_DCB_ASSOCIATION_DIALOG = 842;
- // Screen showing the user's address and the carrier TOS footer.
- PURCHASE_DCB_SETUP_TOS_SCREEN = 843;
- // Button allowing the user to edit the displayed address.
- PURCHASE_DCB_SETUP_EDIT_ADDRESS_BUTTON = 844;
- // Address edit form.
- PURCHASE_DCB_SETUP_EDIT_ADDRESS_SCREEN = 845;
- // Positive button on the address screen.
- PURCHASE_DCB_SETUP_EDIT_ADDRESS_OK_BUTTON = 846;
- // Negative button on the address screen.
- PURCHASE_DCB_SETUP_EDIT_ADDRESS_CANCEL_BUTTON = 847;
- // Positive button on the DCB setup screen.
- PURCHASE_DCB_SETUP_ACCEPT_BUTTON = 848;
- // Negative button on the DCB setup screen.
- PURCHASE_DCB_SETUP_DECLINE_BUTTON = 849;
-
- // Add credit card
- // Hosts a PURCHASE_CC_SETUP_SCREEN.
- PURCHASE_CC_SETUP_DIALOG = 860;
- PURCHASE_CC_SETUP_SCREEN = 861;
- PURCHASE_CC_SETUP_OK_BUTTON = 862;
- PURCHASE_CC_SETUP_CANCEL_BUTTON = 863;
- // Impression logged when displaying an error message to the user.
- PURCHASE_CC_SETUP_ERROR_DIALOG = 864;
- // Impression logged when displaying an error message to the user,
- // together with the choice of canceling the CC screen or editing the
- // entered info and retry.
- PURCHASE_CC_SETUP_ERROR_DIALOG_WITH_CHOICE = 865;
- // Impression logged when errors in the form are highlighted.
- PURCHASE_CC_SETUP_INPUT_ERRORS = 866;
-
- // Redeem code
- // Hosts the redeem code screen.
- // Reserved another range from 1100-1199
- PURCHASE_REDEEM_CODE_DIALOG = 880;
- // The screen where the user enters the gift card / promo code.
- PURCHASE_REDEEM_CODE_SCREEN = 881;
- // "Redeem" button on PURCHASE_REDEEM_CODE_SCREEN.
- PURCHASE_REDEEM_CODE_BUTTON = 882;
- // Screen displaying what the user will get when they continue redemption.
- PURCHASE_REDEEM_CONFIRMATION_SCREEN = 883;
- // "Add to library" button on PURCHASE_REDEEM_CONFIRMATION_SCREEN.
- PURCHASE_REDEEM_CONFIRMATION_BUTTON = 884;
- // Screen showing a success message.
- PURCHASE_REDEEM_SUCCESS_SCREEN = 885;
- // "Watch" / "Install", ..., button on PURCHASE_REDEEM_SUCCESS_SCREEN.
- PURCHASE_REDEEM_SUCCESS_BUTTON = 886;
- // Dialog asking for the user's billing address when redeeming a monetary
- // promo code.
- PURCHASE_REDEEM_ADDRESS_DIALOG = 887;
- // The Input text box on the redeem dialog where user enters the gift
- // card / promo code.
- PURCHASE_REDEEM_CODE_INPUT = 888;
- // "Cancel" button on PURCHASE_REDEEM_CODE_SCREEN.
- PURCHASE_REDEEM_CODE_CANCEL_BUTTON = 889;
- // Country selector menu on address dialog for new wallet account
- // creation.
- PURCHASE_REDEEM_CODE_COUNTRY_MENU = 1101;
- // Name input box on address dialog for new wallet account creation.
- PURCHASE_REDEEM_CODE_NAME_INPUT = 1102;
- // Zip code input box on address dialog for new wallet account creation.
- PURCHASE_REDEEM_CODE_ZIP_INPUT = 1103;
- // 1100 id is available
-
- // Setup Wizard
- // Asks the user to add a credit card.
- SETUP_AVAILABLE_PROMO_OFFER_ACTIVITY = 890;
- // Hosts a PURCHASE_CC_SETUP_SCREEN.
- SETUP_WIZARD_CC_ACTIVITY = 891;
-
- // Notifications
- // Notification shown when there are new updates available. Shown only for
- // users with auto-update disabled.
- NOTIFICATION_NEW_UPDATES = 900;
- // Notification shown when an app has just been succesfully installed.
- NOTIFICATION_SUCCESSFULLY_INSTALLED = 901;
- // Notification shown when an app(s) just been successfully updated.
- NOTIFICATION_SUCCESSFULLY_UPDATED = 902;
- // Notifcation shown when the user has outstanding updates and has not
- // received any new update notifications for a given time interval
- // (e.g. 3 days)
- NOTIFICATION_OUTSTANDING_UPDATES = 903;
- // Notification shown when the user receives new updates that require
- // approval. Shown only for users with auto-update enabled.
- NOTIFICATION_NEW_UPDATES_NEED_APPROVAL = 904;
-
- // Prompt for FOP / Burnsie
- // The dialog shown asking the user to review their account.
- PROMPT_FOR_FOP_DIALOG = 1000;
- // The main activity taking the user through FOP setup.
- PROMPT_FOR_FOP_ACTIVITY = 1001;
- // The main screen on the activity with choices to set up a FOP.
- PROMPT_FOR_FOP_SCREEN = 1002;
- // Message screen shown when the user already has a FOP.
- PROMPT_FOR_FOP_EXISTING_FOP_SCREEN = 1003;
- // Message screen shown when /billingProfile failed.
- PROMPT_FOR_FOP_ERROR_SCREEN = 1004;
- // Success screen shown when the user added a FOP.
- PROMPT_FOR_FOP_SUCCESS_SCREEN = 1005;
- // Continue button at the bottom of the screen.
- PROMPT_FOR_FOP_CONTINUE_BUTTON = 1006;
- // On PROMPT_FOR_FOP_SCREEN, a toggle that expands/collapses the "More"
- // section.
- PROMPT_FOR_FOP_MORE_TOGGLER = 1007;
- // The "None" choice on the PROMPT_FOR_FOP_SCREEN. Visual representation
- // varies by UI mode controlled by experiment.
- PROMPT_FOR_FOP_NONE_ENTRY = 1008;
- // "More details" button at the bottom right, leading to
- // PROMPT_FOR_FOP_MORE_DETAILS_DIALOG
- PROMPT_FOR_FOP_MORE_DETAILS_BUTTON = 1009;
- // A dialog shown when the user clicked
- // PROMPT_FOR_FOP_MORE_DETAILS_BUTTON.
- PROMPT_FOR_FOP_MORE_DETAILS_DIALOG = 1010;
-
- // Ratings and reviews
- // Rate/review section on details page
- RATE_REVIEW_SECTION = 1200;
- // Rating bar on details page that launches the review dialog for a new
- // review
- RATE_REVIEW_SECTION_RATING_BAR = 1201;
- // Review edit button on details page that launches the review dialog to
- // edit a previous review
- RATE_REVIEW_SECTION_EDIT_BUTTON = 1202;
- // Review dialog launched from the details page (Redesigned in MJ)
- RATE_REVIEW_DIALOG_V2 = 1203;
- // Submit button in review dialog to submit a new review
- RATE_REVIEW_DIALOG_SUBMIT_BUTTON = 1204;
- // Save button in review dialog to save edits to an existing review
- RATE_REVIEW_DIALOG_SAVE_BUTTON = 1205;
- // Delete button in review dialog to delete an existing review
- RATE_REVIEW_DIALOG_DELETE_BUTTON = 1206;
- // Cancel action (e.g. back button or tap outside dialog) in review dialog
- RATE_REVIEW_DIALOG_CANCEL = 1207;
- // Rating bar on a card (e.g. Quick Suggestions cluster)
- RATE_REVIEW_CARD_RATING_BAR = 1208;
- }
-
- optional Type type = 1 [default = OTHER];
-
- // A serialized play_store_server.proto:PlaylogStoreNodeDescriptor proto.
- // Note: It is serialized because forcing the Android client to parse it would
- // lose proto fields that that client version doesn't know about.
- optional bytes server_logs_cookie = 2;
-
- // Client can annotate UI elements with arbitrary info.
- optional PlayStoreUiElementInfo client_logs_cookie = 3;
-
- repeated PlayStoreUiElement child = 4;
-}
-
-message PlayStoreImpressionEvent {
- // The DOM tree of the displayed content.
- optional PlayStoreUiElement tree = 1;
-
- // Descriptor path to the node on the previous screen that caused this
- // impression. Each element on the path must have zero children.
- // UI elements are in reversed order, i.e. from leaf to root.
- repeated PlayStoreUiElement referrer_path = 2;
-
- // Id identifies a full playstore impression within a user session. Any
- // impressions sharing the same id will be deduped in the post session
- // analysis. If the id is not set, the impression is considered unique.
- optional int64 id = 3;
-}
-
-message PlayStoreClickEvent {
- // The full path to the clicked UI element on the screen it was displayed on.
- // Each element on the path must have zero children.
- // UI elements are in reversed order, i.e. from leaf to root.
- repeated PlayStoreUiElement element_path = 1;
-}
-
-message PlayStoreSearchEvent {
- // Query text for the search event.
- optional string query = 1;
-
- // Query URL for the search event
- optional string query_url = 2;
-
- // Referrer URL (if known, e.g. from a deeplink)
- optional string referrer_url = 3;
-}
-
-// Deep link event is logged when the external deep link is resolved
-// successfully by the client. The resolved link types are based on the DFE
-// response defined in wireless/android/finsky/proto/dfe/resolve_link.proto,
-// except for LAUNCH_DEEP_LINK which is generated locally when a deep link
-// intent is received.
-message PlayStoreDeepLinkEvent {
- enum ResolvedType {
- OTHER = 0;
- // Deep link resolved to a document details link.
- DETAILS = 1;
- // Deep link resolved to a browse link.
- BROWSE = 2;
- // Deep link resolved to a search link.
- SEARCH = 3;
- // Deep link resolved to a direct purchase.
- DIRECT_PURCHASE = 4;
- // Deep link resolved to Home home.
- HOME_HOME = 5;
- // Deep link resolved to Gift card redemption.
- REDEEM_GIFTCARD = 6;
- // Generated immediately by the intent handler activity.
- // Additional fields package, min_version, new_enough, and can_resolve
- // will be set for this type.
- LAUNCH_DEEP_LINK = 7;
- }
- // The external url receive in the android intent that is sent to the DFE to
- // resolve.
- optional string external_url = 1;
- // The resolved link type from DFE for the external_url.
- optional ResolvedType resolved_type = 2 [default = OTHER];
-
- // The package name (set for LAUNCH_DEEP_LINK)
- optional string package_name = 3;
- // The requested minimum version (set for LAUNCH_DEEP_LINK)
- optional int32 min_version = 4;
- // True if the existing version meets the min version requirement
- // (set for LAUNCH_DEEP_LINK)
- optional bool new_enough = 5;
- // True if the url could be resolved (set for LAUNCH_DEEP_LINK)
- optional bool can_resolve = 6;
-
- // A serialized play_store_server.proto:PlaylogStoreNodeDescriptor proto.
- // See PlayStoreUiElement.server_logs_cookie for details.
- optional bytes server_logs_cookie = 7;
-}
-
-message PlayStoreBackgroundActionEvent {
- enum Type {
- // Housekeeping, etc.
- OTHER = 0;
- SESSION_INFO = 1;
- NLP_REPAIR_STATUS = 2;
-
- // Download, Install, and Restore-related events
- DOWNLOAD_QUEUED = 100;
- DOWNLOAD_START = 101;
- DOWNLOAD_COMPLETE = 102;
- DOWNLOAD_CANCEL = 103;
- DOWNLOAD_ERROR = 104;
- INSTALL_REQUEST = 105;
- INSTALL_START = 106;
- INSTALL_START_ENCRYPTED = 107;
- INSTALL_APPLY_PATCH = 108;
- INSTALL_ACTIVATE = 109;
- INSTALL_FINISHED = 110;
- INSTALL_ERROR = 111;
- INSTALL_ABANDONED = 112;
- RESTORE_SKIP = 113;
- UNINSTALL = 114;
- // Auto update is attempted for a user on auto update over wifi only.
- // Data stored in wifi_auto_update_attempt.
- WIFI_AUTO_UPDATE_ATTEMPT = 115;
- // Auto-Acquire is being attempted as part of a "forcefood" condition.
- // We log two events; One is sent to the "source" (currently owning)
- // account and one is sent to the "dest" (acquiring) account. Both
- // log messages will include the package name and old (installed) and
- // new (offered) version codes.
- AUTO_ACQUIRE_PACKAGE_SOURCE = 116;
- AUTO_ACQUIRE_PACKAGE_DEST = 117;
- // App restore begins with the fetch of data (list of apps) to be restored
- // for a given account. Log the completion of the fetch, error code, and
- // number of attempts. The error codes can be any of the codes defined at
- // https://sites.google.com/a/google.com/universal-store/documentation
- // /android-client/download-error-codes
- RESTORE_FETCH_APP_LIST = 118;
- // Report the result of a self-update check
- // app_data will contain the old (currently installed) version, and the new
- // version if the server provided one. exception_type will be set if there
- // was an error during the RPC.
- SELF_UPDATE_CHECK = 119;
- // Report success/failure of this endpoint call. We log it because it is
- // in the self-update path, so failures here are 'interesting'. If there
- // is an error during the RPC, exception_type will be set.
- DEVICE_CONFIGURATION_UPLOAD = 120;
-
- // Tickles
- TICKLE_PURCHASE_DECLINED = 200;
- TICKLE_PACKAGE_INSTALL = 201;
- TICKLE_PACKAGE_REMOVE = 202;
-
- // Purchase
- //
- // Note that network errors and unexpected server crashes will be reflected
- // in 'exception_type'. Expected server errors (invalid auth tokens,
- // declined purchases, etc.) will be reflected inside server_logs_cookie.
-
- // Free purchase (for free docs not requiring Checkout).
- //
- // These events are logged when the document is added to the user's
- // library. This usually happens only once per document and user (unless
- // ownership is revoked).
- // Specifically, for free apps, these events are triggered only before the
- // very first install by a user, and only if the installation was
- // initiated from the device.
- //
- // Sending request to /purchase
- PURCHASE_FREE_ACQUIRE = 300;
- // Received response from /purchase
- // Includes server_logs_cookie
- PURCHASE_FREE_ACQUIRED = 301;
- // Paid purchase (for paid docs and free docs requiring Checkout)
- //
- // These events are logged as the user progresses through a paid purchase.
- // This usually happens only once per document and user (unless ownership
- // is revoked).
- // Specifically, for paid apps, these events are logged only before the
- // very first install by a user, and only if the purchase is being
- // performed on the device.
- //
- // Sending request to /preparePurchase
- PURCHASE_PREPARE = 302;
- // Received response from /preparePurchase
- // Includes server_logs_cookie
- PURCHASE_PREPARED = 303;
- // Sending request to /commitPurchase
- // Includes server_logs_cookie
- PURCHASE_COMMIT = 304;
- // Received response from /commitPurchase
- // Includes server_logs_cookie
- PURCHASE_COMMITTED = 305;
-
- // Instrument setup
- //
- // Note that 320-323 are logged from billing profile when the user
- // returned from a successful instrument flow. For the "true" background
- // events logged when the instrument is added (also during
- // Setup Wizard), see events starting at 330.
- // The user added a credit card.
- PURCHASE_BILLING_PROFILE_CREDIT_CARD_ADDED = 320;
- // The user set up a DCB instrument.
- PURCHASE_BILLING_PROFILE_CARRIER_BILLING_ADDED = 321;
- // The user redeemed a gift card / promo code.
- PURCHASE_BILLING_PROFILE_CODE_REDEEMED = 322;
- // Play credit purchased (top-up flow finished).
- PURCHASE_BILLING_PROFILE_PLAY_CREDIT_PURCHASED = 323;
-
- // Sending request to /updateInstrument.
- PURCHASE_CC_ADDING = 330;
- // Received success response from /updateInstrument.
- PURCHASE_CC_ADD_SUCCESS = 331;
- // Request to /updateInstrument failed.
- //
- // error_code:
- // 0: Unknown
- // 1: Invalid auth token
- // 2: Volley error during escrowing
- // 3: Volley error during saving
- // 4: Invalid input
- // 5: Error message
- //
- PURCHASE_CC_ADD_ERROR = 332;
-
- // Sending request to /updateInstrument.
- PURCHASE_DCB2_ADDING = 335;
- // Received success response from /updateInstrument.
- PURCHASE_DCB2_ADD_SUCCESS = 336;
- // Request to /updateInstrument failed.
- //
- // error_code:
- // 0: Unknown
- // 1: Volley error
- // 2: Invalid input
- // 3: Error message
- PURCHASE_DCB2_ADD_ERROR = 337;
-
- // Sending request to /updateInstrument.
- PURCHASE_DCB3_ADDING = 340;
- // Received success response from /updateInstrument.
- PURCHASE_DCB3_ADD_SUCCESS = 341;
- // Request to /updateInstrument failed.
- //
- // error_code:
- // 0: Unknown
- // 1: Volley error
- // 2: Invalid input
- // 3: Error message
- PURCHASE_DCB3_ADD_ERROR = 342;
-
- // Prompt for FOP / Burnsie
- //
- // The user added a credit card.
- PURCHASE_PROMPT_FOR_FOP_CREDIT_CARD_ADDED = 350;
- // The user set up a DCB instrument.
- PURCHASE_PROMPT_FOR_FOP_CARRIER_BILLING_ADDED = 351;
- // The user redeemed a gift card / promo code.
- PURCHASE_PROMPT_FOR_FOP_CODE_REDEEMED = 352;
- // Play credit purchased (top-up flow finished).
- // This is entirely unexpected, as we would exit the flow if the user
- // already has an instrument, and top-up requires an instrument.
- PURCHASE_PROMPT_FOR_FOP_PLAY_CREDIT_PURCHASED = 353;
- // The user picked the "None" choice, snoozing the "Prompt for FOP"
- // flow.
- PURCHASE_PROMPT_FOR_FOP_SNOOZED = 354;
- // We entered the "Prompt for FOP" flow and then recognized the user
- // already has a FOP.
- PURCHASE_PROMPT_FOR_FOP_ALREADY_SETUP = 355;
- // We failed to fetch /billingProfile.
- PURCHASE_PROMPT_FOR_FOP_BILLING_PROFILE_ERROR = 356;
-
- // Settings changes
- SETTINGS_PASSWORD_RESTRICT = 400;
- SETTINGS_CONTENT_FILTER = 401;
- SETTINGS_AUTO_UPDATE_GLOBAL = 402;
- SETTINGS_AUTO_UPDATE_APP = 403;
- // Auto-update migration code is running.
- // No "before" or "after" setting values are written here.
- // Reason string indicates "version" for pre-jellybean update;
- // "cleanup" for user-initated cleanup.
- SETTINGS_AUTO_UPDATE_MIGRATED = 404;
- // #405 is retired (was SETTINGS_AUTO_UPDATE_DIALOG_ANSWERED)
- // The user switched accounts. No before/after values.
- SETTINGS_SWITCH_ACCOUNT = 406;
-
- // Misc. background events that are the direct result of user action
- // but are decoupled from the "click: that got there
-
- // Result of redeeming a promo offer (AVAILABLE_PROMO_OFFER_ACTIVITY)
- // If redeemed, operation_success will be set to 'true'
- AVAILABLE_PROMO_OFFER_REDEEMED = 500;
- // Result of entering a content PIN (PIN_ENTRY_DIALOG)
- // If successful, operation_success will be set to 'true'
- PIN_ENTRY_RESULT = 501;
- // Result of GAIA authentication attempt (GAIA_AUTHENTICATION_DIALOG)
- // If successful, operation_success will be set to 'true'
- GAIA_AUTHENTICATION_RESULT = 502;
- // Successful G+ signup. Operation_success will be set to 'true'.
- GPLUS_SIGNED_UP = 503;
- // A WebViewChallenge URL was insecure (not https: or data:)
- // Hostname (not complete URI) will be in "host"
- WEBVIEW_CHALLENGE_NON_HTTPS = 504;
- // User clicked "update all" and we log one message per package
- // (package name in "document" field)
- UPDATE_ALL = 505;
- // User archived documents, and we log one message per doc
- // (package name in "document" field)
- REMOVE_FROM_HISTORY = 506;
- // Widget tracking (enabled, disabled, options, deleted)
- // See widget_event_data for details.
- WIDGET_EVENT = 507;
- // Result of light challenge auth attempt (PURCHASE_AUTH_SCREEN)
- // If successful, operation_success will be set to 'true'
- PURCHASE_AUTH_RESULT = 508;
- // This is used to collect statistics about how often we fetch a
- // 2nd document (for social details) during views of an app details
- // page. The "document" field will indicate the package, and the
- // "operation_success" field will be 'true' for double-fetch, 'false'
- // for a normal (single-fetch) condition.
- DETAILS_2ND_DOCUMENT_FETCH = 509;
- // Search suggestions have been offered. This event will include
- // a message in search_suggestion, which includes items such as the
- // query and the client-observed latency.
- SEARCH_SUGGESTIONS_OFFERED = 510;
- // A search suggestion has been clicked. This event will include
- // a message in search_suggestion, which includes items such as the
- // query and the client-observed latency.
- SEARCH_SUGGESTION_CLICKED = 511;
-
- // An acquisition flow was initiated. This event is logged whenever
- // the user acquires a free or paid item, or goes through an app
- // installation flow.
- //
- // document: ID of the document that is being acquired / installed.
- // offer_type: The offer to acquire. Only set if known upfront.
- // offer_checkout_flow_required: Whether the offer requires a Checkout
- // flow. Note that this flag being true doesn't mean that the user
- // actually went through a purchase screen. For example, users will
- // go through an installation flow without purchase screen when they
- // install a paid app they already own, which would still have
- // offer_checkout_flow_required=true.
- // TODO(chstuder): Add flags for each screen shown during the flow.
- ACQUISITION_FLOW_STARTED = 600;
- // An acquisition flow was finished. This is logged when an acquisition flow
- // marked via ACQUISITION_FLOW_INITIATED has finished.
- //
- // The following fields will be set:
- // document: ID of the document that was acquired / installed.
- // offer_type: Offer type that was acquired.
- // offer_checkout_flow_required: Whether the offer required a Checkout
- // flow. See ACQUISITION_FLOW_STARTED for details.
- // operation_success: 'true' if the acquisition was completed,
- // 'false' otherwise.
- ACQUISITION_FLOW_FINISHED = 601;
- }
- optional Type type = 1 [default = OTHER];
-
- // Additional parameters used by some events
-
- // Flattened Docid (e.g. package name) of document in the event
- optional string document = 2;
-
- // An internal (engineering/debug) annotation of the event.
- optional string reason = 3;
-
- // Error code (HTTP status & other client-internal codes) for error events
- // For more details, see:
- // https://sites.google.com/a/google.com/universal-store/documentation/android-client/download-error-codes
- optional int32 error_code = 4;
-
- // The name of the Java exception that was thrown.
- // Used to communicate client exceptions, network errors and server 500s.
- optional string exception_type = 5;
-
- // The server_logs_cookie as received from the server
- // See PlayStoreUiElement.server_logs_cookie for details.
- optional bytes server_logs_cookie = 6;
-
- // Purchase related
- // The offer type purchased (as ordinal value of finsky.OfferType.Id), see
- // google3/wireless/android/finsky/proto/common.proto.
- // Might be redundant with data in server_logs_cookie, but we won't always
- // have a token.
- optional int32 offer_type = 7;
-
- // For a settings change, an int capturing what the setting changed from.
- // The interpretation of this integer will depend on the type.
- optional int32 from_setting = 8;
-
- // For a settings change, an int capturing what the setting changed to.
- // The interpretation of this integer will depend on the type.
- optional int32 to_setting = 9;
-
- // When a session is initiated, upload all out-of-band session data about
- // the client's current state.
- optional PlayStoreSessionData session_info = 10;
-
- // App data for app-related background events.
- optional AppData app_data = 11;
-
- // For DFE request background events, the server latency as reported via
- // ResponseWrapper.server_metadata.latency_millis.
- optional int64 server_latency_ms = 12;
-
- // For network request background events, the client observed latency.
- optional int64 client_latency_ms = 13;
-
- // For type=NLP_REPAIR_STATUS, more details
- optional NlpRepairStatus nlp_repair_status = 14;
-
- // For success/fail reports (e.g. password auth check) a simple true/false
- optional bool operation_success = 15;
-
- // Host name of server used for a WebViewChallenge. Never the full URL.
- optional string host = 16;
-
- // For type WIDGET_EVENT, data describing the event.
- optional WidgetEventData widget_event_data = 17;
-
- // For type WIFI_AUTO_UPDATE_ATTEMPT, data describing the event.
- optional WifiAutoUpdateAttempt wifi_auto_update_attempt = 18;
-
- // For events that involve retries, a place to note the number of attempts
- optional int32 attempts = 19;
-
- // For acquisition / purchase related operations, whether
- // Offer.checkout_flow_required was 'true' or 'false'.
- optional bool offer_checkout_flow_required = 20;
-
- // For search suggestion events, additional data about the
- // query, latency, etc.
- optional SearchSuggestionReport search_suggestion_report = 21;
-}
-
-message PlayStoreLogEvent {
- // At most one of the following fields should be filled in.
- // Note: tag id 2 can be reused.
-
- // A tree of UI elements displayed on the screen.
- optional PlayStoreImpressionEvent impression = 1;
-
- // An explicit action taken by the user (click, tap, or swipe).
- optional PlayStoreClickEvent click = 3;
-
- // A background action that is interesting enough to be logged, but is not a
- // direct result of an impression or a click.
- optional PlayStoreBackgroundActionEvent background_action = 4;
-
- // A search action performed by the user.
- optional PlayStoreSearchEvent search = 5;
-
- // A deep link event that resolved successfully.
- optional PlayStoreDeepLinkEvent deep_link = 6;
-}
-
-message PlayStoreSessionData {
- // True if the global auto-update setting is enabled on the client.
- optional bool global_auto_update_enabled = 1;
-
- // True if the auto-update over wifi only setting is enabled on the client.
- optional bool global_auto_update_over_wifi_only = 2;
-
- // Number of times the user has been shown the auto-update migration dialog.
- optional int32 auto_update_cleanup_dialog_num_times_shown = 3;
-
- // The network type at the time this event was logged (as provided by
- // the SDK). See Android ConnectivityManager.TYPE_* for values.
- // http://developer.android.com/reference/android/net/ConnectivityManager.html
- optional int32 network_type = 4;
-
- // The network subtype at the time this event was logged (as provided by
- // the SDK). See Android TelephonyManager.NETWORK_TYPE_* for values.
- // http://developer.android.com/reference/android/telephony/TelephonyManager.html
- optional int32 network_sub_type = 5;
-
- // The number of active accounts on the device.
- optional int32 num_accounts_on_device = 6;
-
- // The number of apps that are installed on the device.
- optional int32 num_installed_apps = 7;
-
- // The number of installed apps that have auto-update enabled on the device.
- optional int32 num_auto_updating_installed_apps = 8;
-
- // The number of installed apps that have auto-update disabled on the device.
- optional int32 num_installed_apps_not_auto_updating = 9;
-
- // True if gaia password auth is opted out.
- optional bool gaia_password_auth_opted_out = 10;
-
- // The current content filter level
- optional int32 content_filter_level = 11;
-
- // True if the user has "allow unknown sources" checked
- optional bool allow_unknown_sources = 12;
-
- // "Prompt for FOP" (Burnsie) data
- optional PromptForFopData prompt_for_fop_data = 13;
-}
-
-// This message is added to a PlayStoreBackgroundActionEvent for search
-// suggestions (displayed or clicked).
-message SearchSuggestionReport {
- // The query as entered by the user.
- optional string query = 1;
-
- // The query as rewritten by the suggestion
- optional string suggested_query = 2;
-
- // The client-observed latency.
- optional int64 client_latency_ms = 3;
-}
-
-// This message will be emitted (in a background event) by code that handles
-// Nlp repairs.
-message NlpRepairStatus {
- enum RepairStatus {
- UNKNOWN = 0;
- // The NLP has been found and appears to be functional.
- PROVIDER_FOUND = 1;
- // The NLP is not working, but all other prerequisites are
- // satisfied, and a fix should be applied
- PROVIDER_NEEDS_REPAIR = 2;
- // The NLP is not working, but we are in a holdoff state
- // so no repair will be attempted.
- PROVIDER_REPAIR_HOLDOFF = 3;
- // The device is running the wrong SDK version
- WRONG_SDK_VERSION = 4;
- // The NLP package was not found
- PACKAGE_NOT_FOUND = 5;
- // The NLP package has unexpected package flags
- WRONG_FLAGS = 6;
- // The NLP package has the wrong version #
- WRONG_VERSION = 7;
- // The NLP package has the wrong signature
- WRONG_SIGNATURE = 8;
- // The NLP package is disabled
- PACKAGE_DISABLED = 9;
- }
- optional RepairStatus repair_status = 1 [default = UNKNOWN];
-
- // The package flags of the currently-installed NLP (if found)
- optional int32 flags = 2;
-
- // The version code of the currently-installed NLP (if found)
- optional int32 version_code = 3;
-
- // The signature hash of the currently-installed NLP (if incorrect)
- optional string signature_hash = 4;
-
- // Set to true if test-keys version was found (not set for user builds)
- optional bool found_test_keys = 5;
-
- // Set to true if we are blocked from retry until next boot
- optional bool holdoff_until_boot = 6;
-
- // Set to true if we are blocked from retry until data wipe
- optional bool holdoff_until_wipe = 7;
-
- // Set to true if we have successfully installed the fixer
- optional bool holdoff_after_install = 8;
-
- // The package-enabled bits for the currently-installed NLP
- optional int32 enabled = 9;
-}
-
-message AppData {
- // The app version of the event.
- optional int32 version = 1;
-
- // For installations, the version currently installed on the device.
- //
- // Presence of this field means that this event is about an app update.
- optional int32 old_version = 2;
-
- // True if the currently installed version is a system app.
- optional bool system_app = 3;
-}
-
-// Data to help track usage and changes to widgets
-message WidgetEventData {
- // The various widget classes (map to Java classes)
- enum WidgetClassId {
- UNKNOWN_WIDGET = 0;
- MARKET_WIDGET = 1;
- RECOMMENDED_WIDGET = 2;
- NOWPLAYING_WIDGET = 3;
- }
- // Java class receiving the widget event
- optional WidgetClassId class_id = 1;
-
- // The intent action
- enum IntentActionId {
- UNKNOWN_ACTION = 0;
- ENABLED = 1;
- DISABLED = 2;
- UPDATE_OPTIONS = 3;
- DELETED = 4;
- }
- // The intent action received
- optional IntentActionId intent_action_id = 2;
-
- // Number of widgets
- optional int32 num_widgets = 3;
-
- // The remaining fields are sent only with APPWIDGET_UPDATE_OPTIONS
-
- // Widget type (all, apps, books, movies, music, magazines)
- // These id's will be the same as the values in Common.Backend
- // Or -1 if the string type could not be matched
- optional int32 backendId = 4;
-
- // Min & Max dimensions
- optional int32 min_width = 5;
- optional int32 min_height = 6;
- optional int32 max_width = 7;
- optional int32 max_height = 8;
-}
-
-// Data describing a wifi auto update attempt.
-message WifiAutoUpdateAttempt {
-
- // True if auto update succeeded. False if auto update failed because wifi
- // connecitivty was not available.
- optional bool auto_update_success = 1;
-
- // The number of consecutive failed attempts that have occured since the
- // first failed attempt. Is 1 on first fail.
- optional int32 num_failed_attempts = 2;
-
- // Time passed since first failed attempt. Is 0 on first fail.
- optional int64 time_since_first_fail_ms = 3;
-
- // Time interval of wifi checks
- optional int64 wifi_check_interval_ms = 4;
-}
-
-// Stats about "Prompt for FOP" (Burnsie)
-message PromptForFopData {
- // Whether the user is considered to have a FOP
- // (as determined via DFE /checkInstrument)
- optional bool has_fop = 1;
- // Whether the user added a FOP via Burnsie flow.
- optional bool fop_added = 2;
- // Number of times the "primer" dialog has been shown.
- optional int32 num_dialog_shown = 3;
- // Number of times the actual "Complete your account" screen was shown.
- optional int32 num_fop_selector_shown = 4;
- // Number of times the user snoozed the Burnsie flow.
- optional int32 num_snooze = 5;
-}
diff --git a/PixelPerfect/libs/pixelperfect-api.jar b/PixelPerfect/libs/pixelperfect-api.jar
new file mode 100644
index 0000000..8981cf0
--- /dev/null
+++ b/PixelPerfect/libs/pixelperfect-api.jar
Binary files differ
diff --git a/PixelPerfect/platform/AndroidManifest.xml b/PixelPerfect/platform/AndroidManifest.xml
deleted file mode 100644
index 338cb93..0000000
--- a/PixelPerfect/platform/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.apps.pixelperfect.platform"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_cat"
- android:label="@string/platform_app_name" >
- <service
- android:name=".PixelPerfectPlatform"
- class=".PixelPerfectPlatform"
- android:enabled="true"
- android:exported="true" >
- <intent-filter>
- <action android:name="com.google.android.apps.pixelperfect.api.IPixelPerfectPlatform" />
- </intent-filter>
- </service>
- </application>
-</manifest>
diff --git a/PixelPerfect/platform/tests/Android.mk b/PixelPerfect/platform/tests/Android.mk
deleted file mode 100644
index f94095d..0000000
--- a/PixelPerfect/platform/tests/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_CERTIFICATE := platform
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, ../../tests/src/com/google/android/apps/pixelperfect/api) \
- $(call all-java-files-under, ../../tests/src/com/google/android/apps/pixelperfect/platform)
-
-LOCAL_PACKAGE_NAME := PixelPerfectPlatformTests
-
-LOCAL_INSTRUMENTATION_FOR := PixelPerfectPlatform
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/PixelPerfect/platform/tests/AndroidManifest.xml b/PixelPerfect/platform/tests/AndroidManifest.xml
deleted file mode 100644
index e5c60ec..0000000
--- a/PixelPerfect/platform/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.apps.pixelperfect.platform.tests">
-
- <!-- We add an application tag here just so that we can indicate that
- this package needs to link against the android.test library,
- which is needed when building test cases. -->
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <!--
- This declares that this app uses the instrumentation test runner targeting
- the package of com.example.android.apis. To run the tests use the command:
- "adb shell am instrument -w com.example.android.apis.tests/android.test.InstrumentationTestRunner"
- -->
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.google.android.apps.pixelperfect.platform"
- android:label="Tests for PixelPerfectPlatform."/>
-
-</manifest>
-
diff --git a/PixelPerfect/scripts/eclipse_setup.py b/PixelPerfect/scripts/eclipse_setup.py
index cee2364..31c992d 100755
--- a/PixelPerfect/scripts/eclipse_setup.py
+++ b/PixelPerfect/scripts/eclipse_setup.py
@@ -24,7 +24,7 @@
def main(args):
parser = optparse.OptionParser()
- parser.set_defaults(projects=('pixelperfect','pixelperfect-test','gcore-fp'))
+ parser.set_defaults(projects=('pixelperfect-platform','pixelperfect-platform-test'))
parser.add_option('--platform_src',
help='Location of the android platform source tree')
@@ -44,7 +44,7 @@
else:
output_dir = check_path("%s/../eclipse" % android_root, "eclipse folder",
True)
- output_dir = check_path(("%s/%s") % (output_dir, "pixelperfect"),
+ output_dir = check_path(("%s/%s") % (output_dir, "pixelperfect/platform"),
"project subdirectory", True)
project_root = check_path("%s/.." % scripts_dir, "project root")
print "project_files_dir: %s" % project_files_dir
diff --git a/PixelPerfect/scripts/import_protos.py b/PixelPerfect/scripts/import_protos.py
deleted file mode 100755
index 2e14289..0000000
--- a/PixelPerfect/scripts/import_protos.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/python
-#
-# Imports protos for PixelPerfect and fixes them to work with Android's
-# proto compiler.
-#
-# Adapted from google3/wireless/voicesearch/tools/update_sidekick_proto.py
-
-import os
-import re
-import sys
-
-base_google3_path = "/home/build/google3/"
-files = [
- "net/proto2/bridge/proto/message_set.proto",
- "wireless/android/play/playlog/proto/clientanalytics.proto",
- "wireless/android/play/playlog/proto/personal_application_event.proto",
- "wireless/android/play/playlog/proto/personal_recorder.proto",
- "wireless/android/play/playlog/proto/play_games_client.proto",
- "wireless/android/play/playlog/proto/play_store_client.proto"
-]
-
-# Substitutions are applied in sequence, so later substitutions see effects of
-# earlier ones. This is leveraged to gracefully handle the 'default' options.
-substitutions = [
- # Remove the field option declaration.
- ('extend proto2.FieldOptions {[^}]*}', ''),
- ('extend proto2.EnumValueOptions {[^}]*}', ''),
-
- # Remove options and imports that aren't applicable or supported.
- ('option java_api_version = 2;\n', ''),
- ('option py_api_version = 2;\n', ''),
- ('option cc_api_version = 2;\n', ''),
- ('option java_generate_equals_and_hash = true;\n', ''),
- ('option java_enable_dual_generate_mutable_api = true;\n', ''),
- ('import "java/com/google/apps/jspb/jspb.proto";\n', ''),
- ('import "logs/proto/logs_annotations/logs_annotations.proto";\n', ''),
- ('import "net/proto2/proto/descriptor.proto";\n', ''),
-
- # Remove the message-level logs_proto options.
- ('^\s*option \(logs_proto\.\w*\) = \w*;', ''),
-
- # Leave only default options; temporarily replace []'s with <<</>>>'s.
- ('\[[^]]*?default = ([^]\s,]+)[^]]*\]', '<<<\\1>>>'),
-
- # Leave bracketed expressions in comments alone.
- ('(^\s*//[^\n]*)\[', '\\1{{{'),
-
- # Zap anything between []'s.
- ('\[[^]]*?\]', ''),
-
- # Restore the []'s around default options for the fields.
- ('<<<(.*?)>>>', '[default = \\1]'),
-
- # Restore [ in comments.
- ('{{{', '['),
-
- # Add option optimize_for = LITE_RUNTIME
- ('(syntax = "proto2";\n)', '\\1\noption optimize_for = LITE_RUNTIME;\n'),
-
- # Zap unnecessary whitespace (including newlines). This will sometimes cause
- # lines to become longer than 80 characters, but this is deemed an
- # acceptable style violation since fixing this properly requires more time
- # investment than the payoffs justify.
- ('([0-9])\s+;', '\\1;'),
- ('([0-9])\s+\[', '\\1 ['),
-
- # Zap trailing whitespace.
- (' +$', ''),
-
- # Chomp consecutive newlines.
- ('\n\n\n+', '\n\n')
-]
-
-def update_proto(in_file_path, out_file_path):
- in_file = file(in_file_path)
- proto_source = in_file.read()
- in_file.close()
-
- for pattern, replacement in substitutions:
- regex = re.compile(pattern, re.MULTILINE | re.DOTALL)
- proto_source = regex.sub(replacement, proto_source)
-
- out_file = file(out_file_path, 'w')
- out_file.write(proto_source)
- out_file.close()
-
-def main(args):
- script_path = os.path.realpath(sys.argv[0])
- scripts_dir = os.path.dirname(script_path)
-
- for f in files:
- in_file_path = "%s%s" % (base_google3_path, f)
- out_file_path = os.path.realpath(
- "%s/../imported_protos/src/%s" % (scripts_dir, f))
- update_proto(in_file_path, out_file_path)
- print "processed %s" % f
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/PixelPerfect/scripts/makepp b/PixelPerfect/scripts/makepp
index 4945ef5..c296c92 100755
--- a/PixelPerfect/scripts/makepp
+++ b/PixelPerfect/scripts/makepp
@@ -34,48 +34,24 @@
echo " t = test" >&2
echo " T = uninstall tests" >&2
echo " u = adb uninstall (before install)" >&2
- echo " m = make mockito" >&2
+ echo " m = make dependencies" >&2
echo " c = clean" >&2
exit 0
fi
-# Convert TARGET_PRODUCT to TARGET_DEVICE. If a product isn't listed below,
-# you can add the associated device for it from this list of devices:
-# https://sites.google.com/a/google.com/android/development/codebook
-product=$TARGET_PRODUCT
-
-if [[ $product == hammerhead ]]; then
- device=hammerhead
-elif [[ $product == occam ]]; then
- device=mako
-elif [[ $product == nakasi ]]; then
- device=grouper
-elif [[ $product == nakasig ]]; then
- device=tilapia
-elif [[ $product == razor ]]; then
- device=flo
-elif [[ $product == razorg ]]; then
- device=deb
-elif [[ $product == mantaray ]]; then
- device=manta
-else
- echo "Unknown product:"$product
- exit 1;
-fi
-
build=
install=
uninstall=
runtests=
uninstall_tests=
-make_mockito=
+make_dependencies=
clean=
# Explode the command line params in case they are all jammed together in
# one parameter.
[[ $* =~ c ]] && clean=1 && echo Clean
-[[ $* =~ m ]] && make_mockito=1 && echo Making mockito
+[[ $* =~ m ]] && make_dependencies=1 && echo Making dependencies
[[ $* =~ b ]] && build=1 && echo Building
[[ $* =~ u ]] && uninstall=1 && echo Uninstalling
[[ $* =~ T ]] && uninstall_tests=1 && echo Uninstall Tests
@@ -88,16 +64,13 @@
rm -rf out/target/common/obj/APPS/PixelPerfect*;
rm -rf out/target/common/obj/JAVA_LIBRARIES/*pixelperfect*
rm -rf out/target/product/*/data/app/PixelPerfect*"
-[[ -n "$make_mockito" ]] && make mockito-target
+[[ -n "$make_dependencies" ]] && mmm external/protobuf:libprotobuf-java-2.3.0-lite &&
+ mmma vendor/unbundled_google/packages/PrebuiltGmsCore &&
+ make mockito-target &&
+ make android-support-test
[[ -n "$build" ]] && mmm packages/experimental/PixelPerfect
-[[ -n "$uninstall" ]] && bash -xc "
- adb uninstall com.google.android.apps.pixelperfect;
- adb uninstall com.google.android.apps.pixelperfect.platform;"
-[[ -n "$uninstall_tests" ]] && bash -xc "
- adb uninstall com.google.android.apps.pixelperfect.tests;
- adb uninstall com.google.android.apps.pixelperfect.platform.tests;"
-[[ -n "$install" ]] && bash -xc "
- adb install -r out/target/product/$device/system/app/PixelPerfect.apk;
- adb install -r out/target/product/$device/system/app/PixelPerfectPlatform.apk;"
+[[ -n "$uninstall" ]] && bash -xc "adb uninstall com.google.android.apps.pixelperfect.platform"
+[[ -n "$uninstall_tests" ]] && bash -xc "adb uninstall com.google.android.apps.pixelperfect.platform.tests"
+[[ -n "$install" ]] && bash -xc "adb install -r out/target/product/generic/system/app/PixelPerfectPlatform.apk"
[[ -n "$runtests" ]] && runtest --path packages/experimental/PixelPerfect
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/AccessibilityEventProcessor.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/AccessibilityEventProcessor.java
deleted file mode 100644
index 644a6fe..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/AccessibilityEventProcessor.java
+++ /dev/null
@@ -1,444 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.google.android.gms.playlog.PlayLogger;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.logging.RecordedEvent.RecordedRect;
-import com.google.common.logging.RecordedEvent.RecordedTypes.WidgetType;
-import com.google.common.logging.RecordedEvent.RecordedUpdate;
-import com.google.common.logging.RecordedEvent.RecordedUpdate.Type;
-import com.google.common.logging.RecordedEvent.Screenshot;
-import com.google.common.logging.RecordedEvent.UIElement;
-import com.google.protobuf.CodedOutputStream;
-import com.google.wireless.android.play.playlog.proto.ClientAnalytics;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-/**
- * Processes {@link AccessibilityEvent}s:
- * <ul>
- * <li> Filters out events that should not be published in Clearcut.
- * <li> Publishes the surviving events.
- * </ul>
- *
- * <p>This class is state-less and thread safe. It is used as a singleton, because it is
- * instantiated only in one place, namely AccessibilityEventService, which itself is a singleton.
- */
-public class AccessibilityEventProcessor {
-
- private static final String TAG = "PixelPerfect.AccessibilityEventProcessor";
-
- /** Version for the recorded updates .*/
- // TODO(stlafon): We should be using something like "android:major.minor".
- private static final String VERSION = "0.1";
-
- /** Maps the name of a widget to its enum type. */
- private static final Map<String, WidgetType> widgetTypeMap = getWidgetTypeMap();
-
- /**
- * Wrapper around {@link PlayLogger}. Unlike the latter, it's not final, so it can be mocked.
- */
- public static class ClearcutLogger {
-
- private final PlayLogger mPlayLogger;
-
- ClearcutLogger(Context context, int logSource, String accountName,
- @Nullable PlayLogger.LoggerCallbacks loggerCallbacks) {
- mPlayLogger = new PlayLogger(
- context,
- logSource,
- accountName,
- loggerCallbacks);
- }
-
- public void start() {
- mPlayLogger.start();
- }
-
- public void logEvent(byte[] bytes) {
- mPlayLogger.logEvent(null, bytes);
- }
- }
-
- /**
- * Maps an {@link AccessibilityEvent} type (integer value) to a {@link RecordedUpdate}'s
- * {@link Type}.
- */
- private static final SparseArray<RecordedUpdate.Type> eventTypeMapping =
- getEventTypeConversionArray();
-
- /** The packages excluded for which no data is collected. */
- private final ExcludedPackages mExcludedPackages;
-
- /** Clearcut Logger for recording events. */
- private final ClearcutLogger mLogger;
-
- /** The type of the last AccessibilityEvent we received */
- private int mLastEventType = -1;
-
- /** The UIElement corresponding to the last AccessibilityEvent we received. */
- private UIElement mLastElement = UIElement.newBuilder().build();
-
- /** Client for communicating with PixelPerfectPlatform service, e.g., for screenshots.*/
- private PlatformServiceClient mPlatformServiceClient;
-
- public AccessibilityEventProcessor(Context context, String accountName,
- ExcludedPackages excludedPackages,
- @Nullable PlatformServiceClient platformServiceClient,
- @Nullable PlayLogger.LoggerCallbacks loggerCallbacks) {
- this(excludedPackages, platformServiceClient, new ClearcutLogger(
- context,
- ClientAnalytics.LogRequest.LogSource.PERSONAL_LOGGER.getNumber(),
- accountName, loggerCallbacks));
- }
-
- @VisibleForTesting
- AccessibilityEventProcessor(
- ExcludedPackages excludedPackages,
- @Nullable PlatformServiceClient platformServiceClient,
- ClearcutLogger logger) {
- mExcludedPackages = excludedPackages;
- mPlatformServiceClient = platformServiceClient;
- mLogger = logger;
- mLogger.start();
- }
-
- /**
- * Obtains a screenshot by calling the platform service.
- * @return captured screenshot proto. {@code null} if screenshot was not captured.
- */
- @Nullable
- private Screenshot obtainScreenshot() {
- if (mPlatformServiceClient != null) {
- try {
- return mPlatformServiceClient.obtainScreenshot();
- } catch (SecurityException e) {
- // TODO(mukarram) Should we catch this or let the app crash?
- Log.e(TAG, "SecurityException while obtaining screenshot. " + e);
- } catch (IllegalStateException e) {
- Log.e(TAG, "mPlatformServiceClient is not ready. " + e);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException: ", e);
- }
- }
- return null;
- }
-
- /**
- * Processes an {@link AccessibilityEvent}.
- *
- * @param event {@link AccessibilityEvent} to process
- */
- public void process(AccessibilityEvent event) {
- Screenshot screenshot = obtainScreenshot();
- if (excludeEvent(event)) {
- return;
- }
-
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
- publishWindowChanged(event, screenshot);
- } else {
- publishSingleEvent(event, screenshot);
- }
- mLastEventType = event.getEventType();
- }
-
- /**
- * Returns whether the {@link AccessibilityEvent} should be excluded.
- *
- * @param event the {@link AccessibilityEvent}
- * @return true if the event should be excluded
- */
- private boolean excludeEvent(AccessibilityEvent event) {
- if (mExcludedPackages.isExcluded(event.getPackageName().toString())) {
- Log.v(TAG, "Excluding package " + event.getPackageName());
- return true;
- }
- // Filter out text selections - see comment in publishWindowChanged().
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED) {
- return true;
- }
- // Note, we could also filter based on field name, e.g. 'isPassword' etc...
- return false;
- }
-
- /**
- * Creates and returns a {@link RecordedUpdate}.
- *
- * @param event the {@link AccessibilityEvent}
- * @param element {@UIElement} in which to fill the update.
- * @return the {@link RecordedUpdate} or null if the event type is unknown.
- */
- private RecordedUpdate createUpdate(AccessibilityEvent event, UIElement element) {
- // Get the {@code RecordedUpdate}'s type.
- Type eventType = eventTypeMapping.get(event.getEventType());
-
- if (eventType == null) {
- Log.v(TAG, "Not logging unknown event with type = " + event.getEventType());
- return null;
- }
-
- Log.v(TAG, "RecordedUpdate with " + event.getEventType() + " --> " + eventType);
-
- RecordedUpdate.Builder updateBuilder = RecordedUpdate.newBuilder()
- .setType(eventType)
- .setElement(element)
- .setVersion(VERSION);
-
- if (event.getPackageName() != null) {
- updateBuilder.setPackageName(event.getPackageName().toString());
- }
-
- return updateBuilder.build();
- }
-
- /**
- * Publishes an event that's not a change of window content. This is typically an interaction
- * with a given widget.
- *
- * @param event the {@link AccessibilityEvent} to publish
- * @param screenshot the {@link Screenshot} to go with this event.
- */
- private void publishSingleEvent(
- AccessibilityEvent event,
- @Nullable Screenshot screenshot) {
- AccessibilityNodeInfo node = event.getSource();
- if (node == null) {
- return;
- }
- RecordedUpdate update = createUpdate(event, createUIElement(node, screenshot, false));
- if (update != null) {
- publishUpdate(update);
- }
- node.recycle();
- }
-
- /**
- * Publishes an {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}.
- *
- * @param event the {@link AccessibilityEvent} to publish
- * @param screenshot the {@link Screenshot} to go with this event.
- */
- private void publishWindowChanged(
- AccessibilityEvent event,
- @Nullable Screenshot screenshot) {
- AccessibilityNodeInfo node = event.getSource();
- if (node == null) {
- return;
- }
- AccessibilityNodeInfo parent = node;
- while (parent.getParent() != null) {
- parent = parent.getParent();
- }
- UIElement newElement = createUIElement(parent, screenshot, true);
- // TODO(stlafon, mukarram) Verify that .equals() is a deep comparison.
- if (!newElement.equals(mLastElement)) {
- // We get window-changed events following on from a text changed event. We
- // don't want to process every one of these, so skip printing if the last
- // event was a text change. Note that we strip selection_change events -
- // sometimes we get these after a text change and sometimes we don't.
- if (mLastEventType != AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) {
- RecordedUpdate update = createUpdate(event, newElement);
- if (update != null) {
- publishUpdate(update);
- }
- }
- mLastElement = newElement;
- }
- node.recycle();
- }
-
- /**
- * Publishes a {@link RecordedUpdate} to Clearcut.
- *
- * @param update the {@link RecordedUpdate} to publish
- */
- private void publishUpdate(RecordedUpdate update) {
- printUIElement("", update.getElement());
-
- // Publish to Clearcut.
- byte[] buffer = new byte[update.getSerializedSize()];
- CodedOutputStream outputStream = CodedOutputStream.newInstance(buffer);
- try {
- update.writeTo(outputStream);
- mLogger.logEvent(buffer);
- Log.v(TAG, "Wrote " + buffer.length + " bytes in Clearcut.");
- } catch (IOException e) {
- Log.e(TAG, "Failed to write update of type " + update.getType() + " : " + e);
- }
- }
-
- /**
- * Returns true if the content of the {@link AccessibilityNodeInfo} should
- * be elided. This is desirable for sensitive UIElements, such as passwords.
- *
- * Note: this function is mostly heuristics; there is no guarantee that this
- * removes all sensitive information.
- *
- * @param node the input {@link AccessibilityNodeInfo}
- * @return true if content should be elided.
- */
- @VisibleForTesting
- boolean shouldElideContent(AccessibilityNodeInfo node) {
- // for now, only thing we check for is whether the node is a password node.
- return node.isPassword();
- }
-
- /**
- * Creates a {@link UIElement} message from an {@link AccessibilityNodeInfo}. Creates child
- * nodes if {@code andChildren} is true. Note that many of the fields in
- * {@link AccessibilityNodeInfo} can be null, so check before we set them.
- *
- * @param node the input {@link AccessibilityNodeInfo}
- * @param screenshot the {@link Screenshot} to go with this element.
- * @param createChildren whether to create child nodes
- * @return the {@link UIElement}
- */
- @VisibleForTesting
- UIElement createUIElement(
- AccessibilityNodeInfo node,
- @Nullable Screenshot screenshot,
- boolean createChildren) {
- UIElement.Builder elementBuilder = UIElement.newBuilder();
- if (widgetTypeMap.containsKey(node.getClassName())) {
- elementBuilder.setClassType(widgetTypeMap.get(node.getClassName()));
- } else {
- elementBuilder.setClassName(node.getClassName().toString());
- }
- // Note, getViewIdResourceName() requires API level 18.
- if (node.getViewIdResourceName() != null) {
- elementBuilder.setResourceName(node.getViewIdResourceName());
- }
- if (node.getContentDescription() != null) {
- elementBuilder.setDescription(node.getContentDescription().toString());
- }
-
- final boolean elideContent = shouldElideContent(node);
-
- if (elideContent) {
- elementBuilder.setContentElided(true);
- }
-
- if (node.getText() != null && !elideContent) {
- elementBuilder.setContent(node.getText().toString());
- }
-
- if (screenshot != null) {
- elementBuilder.setScreenshot(screenshot);
- }
-
- Rect rect = new Rect();
- node.getBoundsInParent(rect);
- RecordedRect recordedRect = RecordedRect.newBuilder()
- .setBottom(rect.bottom)
- .setLeft(rect.left)
- .setRight(rect.right)
- .setTop(rect.top)
- .build();
- elementBuilder.setRect(recordedRect);
- if (createChildren) {
- int numChildren = node.getChildCount();
- for (int i = 0; i < numChildren; i++) {
- AccessibilityNodeInfo child = node.getChild(i);
- if (child != null) {
- // Currently, we set the screenshot only on the root
- // UIElement object, hence passing null to the children.
- elementBuilder.addChild(createUIElement(child, null, true));
- child.recycle();
- } else {
- // Create an empty element to represent the null child
- elementBuilder.addChild(UIElement.newBuilder().build());
- }
- }
- }
- return elementBuilder.build();
- }
-
- /** Prints a {@link UIElement} in the logcat. */
- private void printUIElement(String indent, UIElement node) {
- String className = (node.getClassType() == WidgetType.CUSTOM
- ? node.getClassName() : "" + node.getClassType());
- Log.v(TAG, indent + className + " (" + node.getResourceName() + ") "
- + node.getDescription()
- // Do not print if content is null
- + (node.getContent() == null ? "" : " = " + node.getContent())
- // If content was elided print that it was elided so that
- // the reader is not confused.
- + (node.getContentElided() ? "<Content Elided>" : "")
- // If the node has screenshot, then print the size in bytes.
- + (node.hasScreenshot() ? "Screenshot size (bytes): " + node.getScreenshot().getSerializedSize() : ""));
- for (UIElement child : node.getChildList()) {
- printUIElement(indent + " ", child);
- }
- }
-
- /**
- * Creates and returns a {@link Map} from a widget to its enum type.
- */
- private static Map<String, WidgetType> getWidgetTypeMap() {
- Map<String, WidgetType> map = new HashMap<String, WidgetType>();
-
- map.put("android.appwidget.AppWidgetHostView", WidgetType.APP_WIDGET_HOST_VIEW);
- map.put("android.view.View", WidgetType.VIEW);
- map.put("android.webkit.WebView", WidgetType.WEB_VIEW);
- map.put("android.widget.Button", WidgetType.BUTTON);
- map.put("android.widget.CheckBox", WidgetType.CHECK_BOX);
- map.put("android.widget.CheckedTextView", WidgetType.CHECKED_TEXT_VIEW);
- map.put("android.widget.EditText", WidgetType.EDIT_TEXT);
- map.put("android.widget.FrameLayout", WidgetType.FRAME_LAYOUT);
- map.put("android.widget.HorizontalScrollView",
- WidgetType.HORIZONTAL_SCROLL_VIEW);
- map.put("android.widget.ImageButton", WidgetType.IMAGE_BUTTON);
- map.put("android.widget.ImageView", WidgetType.IMAGE_VIEW);
- map.put("android.widget.LinearLayout", WidgetType.LINEAR_LAYOUT);
- map.put("android.widget.ListView", WidgetType.LIST_VIEW);
- map.put("android.widget.MultiAutoCompleteTextView",
- WidgetType.MULTI_AUTO_COMPLETE_TEXT_VIEW);
- map.put("android.widget.ProgressBar", WidgetType.PROGRESS_BAR);
- map.put("android.widget.RelativeLayout", WidgetType.RELATIVE_LAYOUT);
- map.put("android.widget.ScrollView", WidgetType.SCROLL_VIEW);
- map.put("android.widget.Spinner", WidgetType.SPINNER);
- map.put("android.widget.Switch", WidgetType.SWITCH);
- map.put("android.widget.TabHost", WidgetType.TAB_HOST);
- map.put("android.widget.TabWidget", WidgetType.TAB_WIDGET);
- map.put("android.widget.TextView", WidgetType.TEXT_VIEW);
- map.put("android.widget.ViewSwitcher", WidgetType.VIEW_SWITCHER);
-
- return map;
- }
-
- /**
- * Creates and returns a {@link SparseArray} from {@link AccessibilityEvent}'s event types to
- * {@link RecordedUpdate}'s {@link Type}.
- */
- private static SparseArray<Type> getEventTypeConversionArray() {
- SparseArray<Type> sparseArray = new SparseArray<Type>();
-
- sparseArray.put(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED,
- Type.TYPE_NOTIFICATION_STATE_CHANGED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_CLICKED, Type.TYPE_VIEW_CLICKED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_FOCUSED, Type.TYPE_VIEW_FOCUSED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, Type.TYPE_VIEW_LONG_CLICKED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_SCROLLED, Type.TYPE_VIEW_SCROLLED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_SELECTED, Type.TYPE_VIEW_SELECTED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, Type.TYPE_VIEW_TEXT_CHANGED);
- sparseArray.put(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED,
- Type.TYPE_VIEW_TEXT_SELECTION_CHANGED);
- sparseArray.put(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
- Type.TYPE_WINDOW_CONTENT_CHANGED);
-
- return sparseArray;
- }
-
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/AccessibilityEventService.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/AccessibilityEventService.java
deleted file mode 100644
index 187839c..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/AccessibilityEventService.java
+++ /dev/null
@@ -1,326 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import com.google.android.apps.pixelperfect.util.RealClock;
-import com.google.android.apps.pixelperfect.preferences.PreferencesActivity;
-import com.google.android.gms.playlog.PlayLogger;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.Toast;
-import android.util.Log;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Sets;
-
-import java.util.Locale;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Listens to {@link AccessibilityEvent}s triggered when there's a state
- * transition in the UI.
- */
-public class AccessibilityEventService extends AccessibilityService
- implements PlayLogger.LoggerCallbacks {
-
- private static final String TAG = "PixelPerfect.AccessibilityEventService";
-
- /** Action for pausing the recording. */
- @VisibleForTesting
- static final String ACTION_PAUSE = "com.google.android.apps.pixelperfect.PAUSE";
-
- /** Action for resuming the recording. */
- @VisibleForTesting
- static final String ACTION_RESUME = "com.google.android.apps.pixelperfect.RESUME";
-
- /** The unique id for the sticky notification. */
- private static final int NOTIFICATION_ID = 0;
-
- /**
- * If true, then we don't record anything (screenshots, accessibility events...). This allows
- * users to go enter the incognito mode.
- */
- private static boolean sIsPaused;
-
- /** A {@link Toast} shown when the service is paused or resumed. */
- private static Toast sToast;
-
- /**
- * The event processor. If the device doesn't have a Google corp account,
- * then this variable will be {@code null}, and no publishing in Clearcut
- * will occur.
- */
- private AccessibilityEventProcessor mProcessor;
-
- /** The excluded packages. */
- private ExcludedPackages mExcludedPackages;
-
- /** Used to create the sticky notification. */
- private NotificationManager mNotificationManager;
-
- /** Client for PixelPerfectPlatform service.*/
- private PlatformServiceClient mPlatformServiceClient;
-
- /**
- * Whitelist of usernames allowed to use the app. Should be kept sorted alphabetically.
- * This list is a snapshot of users in the pixel-perfect@google.com group.
- * TODO(dprothro): enforce this constraint using gservices and a google group.
- */
- private static final Set<String> USERNAME_WHITELIST = Sets.newHashSet(
- "aayushkumar@google.com",
- "ababu@google.com",
- "abednego@google.com",
- "adzic@google.com",
- "agoyal@google.com",
- "alasdair@google.com",
- "alpha@google.com",
- "andys@google.com",
- "aoun@google.com",
- "aparnacd@google.com",
- "bhorling@google.com",
- "chsnow@google.com",
- "davidmonsees@google.com",
- "dbailey@google.com",
- "divye@google.com",
- "djmarcin@google.com",
- "dmauro@google.com",
- "dprothro@google.com",
- "dramage@google.com",
- "ertoz@google.com",
- "etaropa@google.com",
- "girirao@google.com",
- "levesque@google.com",
- "lynnc@google.com",
- "maureen@google.com",
- "meliss@google.com",
- "mukarram@google.com",
- "panda@google.com",
- "purui@google.com",
- "rajan@google.com",
- "ram@google.com",
- "riteshg@google.com",
- "sidds@google.com",
- "smyang@google.com",
- "stlafon@google.com",
- "venkataraman@google.com",
- "wei@google.com",
- "wenjieli@google.com",
- "wisam@google.com",
- "xban@google.com",
- "yantao@google.com",
- "yezhao@google.com");
-
- @Override
- public void onCreate() {
- Log.v(TAG, "onCreate");
-
- // The publishing of accessibility events in Clearcut is only enabled
- // if the device has a whitelisted account.
- String accountName = getAccountName();
- if (accountName != null) {
- mPlatformServiceClient = new PlatformServiceClient(this, new RealClock());
- // No need to synchronize this as the #onCreate method will only be
- // called when the service is enabled in the settings, so it should
- // be safe from concurrency issues.
- try {
- mExcludedPackages = ExcludedPackages.getInstance(this);
- mProcessor = new AccessibilityEventProcessor(
- this, accountName, mExcludedPackages, mPlatformServiceClient,
- this);
- } catch (Exception e) {
- int msgId = ((e instanceof IllegalStateException)
- && e.getMessage().contains("com.google.android.gms.version"))
- ? R.string.gmscore_version_error
- : R.string.initialization_error;
- Log.e(TAG, "Failed to initialize PixelPerfect", e);
- showToast(msgId);
- stopSelf();
- return;
- }
- mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- setIsPaused(false);
- showToast(R.string.pixelperfect_running);
- } else {
- showToast(R.string.unauthorized);
- }
- }
-
- // TODO(stlafon): Understand why this method is never called after the onStartCommand() method
- // is invoked (e.g. when the user clicks on pause/resume in the notification). The problem is
- // that the notification doesn't get canceled if the following sequence happens:
- // Enable service in settings -> Click on pause in notification -> Disable service in settings
- @Override
- public void onDestroy() {
- Log.v(TAG, "onDestroy");
-
- // Cancel the sticky notification.
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
- // Inform the user that PixelPerfect is no longer running.
- showToast(R.string.pixelperfect_not_running);
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.v(TAG, "onStartCommand");
-
- if (intent != null) {
- if (ACTION_PAUSE.equals(intent.getAction())) {
- setIsPaused(true);
- } else if (ACTION_RESUME.equals(intent.getAction())) {
- setIsPaused(false);
- }
- }
-
- // The following will not stop the service, as the latter is not started by a call to
- // startService(). Rather, it is enabled from the system settings. Calling stopSelf() here
- // undoes the effect of onStartCommand(), which gets called each time the user clicks on
- // pause/resume in the notification.
- stopSelf();
-
- // We want this service to continue running until it is explicitly stopped,
- // so return sticky.
- return START_STICKY;
- }
-
- @Override
- public void onServiceConnected() {
- Log.v(TAG, "onServiceConnected " + getServiceInfo());
- }
-
- @Override
- public void onInterrupt() {
- Log.v(TAG, "onInterrupt");
- }
-
- @Override
- public void onAccessibilityEvent(AccessibilityEvent event) {
- if (mProcessor != null && !getIsPaused()) {
- mProcessor.process(event);
- }
- }
-
- /**
- * Atomically:
- * <ul>
- * <li> sets the value of {@link #sIsPaused},
- * <li> updates the sticky notification,
- * <li> shows a toast informing the user of the new state.
- * </ul>
- *
- * <p>This does not stop the {@link AccessibilityService}. It just prevents us from recording
- * any event. To stop the service, users need to go to the system settings and manually disable.
- * Note, calling {@link #stopSelf()} in this method doesn't seem to do anything.
- *
- * @param isPaused whether the recording is paused or not
- */
- @VisibleForTesting
- synchronized void setIsPaused(boolean isPaused){
- sIsPaused = isPaused;
- mNotificationManager.notify(NOTIFICATION_ID, createNotification(sIsPaused));
-
- int msgId = sIsPaused ? R.string.user_in_incognito : R.string.user_not_incognito;
- showToast(msgId);
- }
-
- @VisibleForTesting
- synchronized boolean getIsPaused() {
- return sIsPaused;
- }
-
- /**
- * If a whitelisted account is linked to this device, returns the account name. Otherwise,
- * returns {@code null}.
- */
- @Nullable private String getAccountName() {
- AccountManager manager = AccountManager.get(this);
- return getAccountNameImpl(manager.getAccounts());
- }
-
- /** Same as {@link #getAccountName()}, but acts on an array of {@link Account}s. */
- @VisibleForTesting
- @Nullable String getAccountNameImpl(Account[] accounts) {
- for (Account account : accounts) {
- if (USERNAME_WHITELIST.contains(account.name.toLowerCase(Locale.ENGLISH))) {
- return account.name;
- }
- }
- return null;
- }
-
- /**
- * Creates and returns a permanent (sticky) notification that features two buttons:
- * <ul>
- * <li> A button to pause/resume data recording (pausing == going incognito).
- * <li> A button to launch the preferences activity, where users can set a blacklist of apps.
- * </ul>
- *
- * @param isPaused whether recording is currently paused or not
- * @return the {@link Notification}
- */
- @VisibleForTesting
- Notification createNotification(boolean isPaused) {
- int smallIconId = isPaused ? R.drawable.ic_no_cat : R.drawable.ic_cat;
-
- Intent intent = new Intent(this, PreferencesActivity.class);
- PendingIntent prefsPendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
-
- intent = new Intent(this, AccessibilityEventService.class)
- .setAction(isPaused ? ACTION_RESUME : ACTION_PAUSE);
- PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent, 0);
-
- CharSequence pauseOrResume = isPaused ? getText(R.string.resume) : getText(R.string.pause);
- int pauseOrResumeIcon = isPaused ? R.drawable.ic_resume : R.drawable.ic_pause;
- CharSequence notifDescription =
- isPaused ? getText(R.string.is_paused) : getText(R.string.is_running);
-
- return new Notification.Builder(this)
- .setContentTitle(getText(R.string.notification_title))
- .setContentText(notifDescription)
- .setSmallIcon(smallIconId)
- .setOngoing(true) // cannot be dismissed
- .addAction(pauseOrResumeIcon, pauseOrResume, servicePendingIntent)
- .addAction(R.drawable.ic_preferences, getText(R.string.notif_preferences),
- prefsPendingIntent)
- .build();
- }
-
- /** Shows a {@link Toast}. */
- private void showToast(int msgId) {
- if (sToast == null) {
- sToast = Toast.makeText(this, msgId, Toast.LENGTH_SHORT);
- } else {
- sToast.setText(msgId);
- }
- sToast.show();
- }
-
- @Override
- public void onLoggerConnected() {
- Log.v(TAG, "PlayLogger connected");
- }
-
- @Override
- public void onLoggerFailedConnectionWithResolution(PendingIntent resolutionIntent) {
- // TODO(dprothro): call the PendingIntent to see if the user will approve
- // usage of the PlayLogger.
- Log.e(TAG, "Failed to initialize PixelPerfect - loggerFailedConnectionWithResolution");
- showToast(R.string.initialization_error);
- stopSelf();
- }
-
- @Override
- public void onLoggerFailedConnection() {
- Log.e(TAG, "Failed to initialize PixelPerfect - loggerFailedConnection");
- showToast(R.string.initialization_error);
- stopSelf();
- }
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/ExcludedPackages.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/ExcludedPackages.java
deleted file mode 100644
index bb5bba3..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/ExcludedPackages.java
+++ /dev/null
@@ -1,214 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * Access layer for the list of packages whose events should not be published to Clearcut.
- * This class maintains 2 exclusion sets:
- * <ul>
- * <li>A hardcoded set of packages ("hardcoded exclusion set"), containing packages whose data
- * must absolutely be excluding from logging (e.g. the screenlock key guard). Users cannot control
- * the content of that set.
- * <li>A custom set of packages ("custom exclusion set"), to which the user can freely add and
- * remove packages.
- * </ul>
- *
- * <p>The custom exclusion set is ultimately stored on the internal storage of the device. So
- * it's a per-device set. Note that it should be made a per-user set that we store in the cloud.
- *
- * <p>This class is a singleton.
- */
-@ThreadSafe
-public class ExcludedPackages {
-
- private static final String TAG = "PixelPerfect.ExcludedPackages";
-
- /**
- * The internal storage file that contains the comma-separated list of excluded packages, when
- * the app is running (not in the tests).
- */
- private static final String EXCLUDED_PACKAGES_FILENAME = "excluded_packages.csv";
-
- /** Delimiter used in the storage file. */
- private static final String DEMILITER = ",";
-
- /** Shared instance of this service. */
- private static ExcludedPackages sSharedInstance;
-
- /** Hardcoded packages. For apps that must absolutely be excluded. */
- private final Set<String> mHardcodedPackages;
-
- /** Packages that can be added or removed by the user. */
- private final Set<String> mCustomPackages;
-
- /** Filename where the exclusion list is stored. */
- private final String mStorageFilename;
-
- /** Context to hold on to for reading the storage file. */
- private Context mContext;
-
- /**
- * Gets the instance to be used in the application. Do not use in tests! Instead, call the
- * constructor below, and pass a custom filename (different from
- * {@link #EXCLUDED_PACKAGES_FILENAME}).
- */
- public synchronized static ExcludedPackages getInstance(Context context) {
- if (sSharedInstance == null) {
- sSharedInstance = new ExcludedPackages(getHarcodedPackages(), context,
- EXCLUDED_PACKAGES_FILENAME);
- }
- // Use the latest context. This will make it more likely that we're not using a context
- // that's already been destroyed.
- sSharedInstance.mContext = context;
- return sSharedInstance;
- }
-
- @VisibleForTesting
- ExcludedPackages(Set<String> harcodedPackages, Context context, String fileName) {
- mHardcodedPackages = harcodedPackages;
- mCustomPackages = new HashSet<String>();
- mContext = context;
- mStorageFilename = fileName;
- readFromFile();
-
- if (sSharedInstance != null) {
- Log.e(TAG, "Shared ExcludedPackages instance already exists!");
- }
- sSharedInstance = this;
- }
-
- /**
- * Reads the custom exclusion set from the internal storage, and use it to populate the
- * current state.
- */
- public synchronized void readFromFile() {
- try {
- FileInputStream inputStream = mContext.openFileInput(mStorageFilename);
- InputStreamReader isr = new InputStreamReader(inputStream);
- BufferedReader bufferedReader = new BufferedReader(isr);
- String line;
- // Note: We expect at most one line in the file.
- line = bufferedReader.readLine();
- mCustomPackages.clear();
- if (line != null) {
- mCustomPackages.addAll(Arrays.asList(line.split(DEMILITER)));
- }
- } catch (FileNotFoundException e) {
- // The file hasn't been created yet. Just do nothing. It will be created next time
- // a package is added to the custom exclusion set.
- } catch (IOException e) {
- Log.e(TAG, "Unable to read the excluded packages: " + e);
- }
- }
-
- /**
- * Returns whether a package should be excluded from logging.
- *
- * @param packageName the package name
- */
- public synchronized boolean isExcluded(String packageName) {
- return mHardcodedPackages.contains(packageName)
- || mCustomPackages.contains(packageName);
- }
-
- /**
- * Returns a list containing the packages from the custom exclusion set. Hardcoded packages are
- * not returned.
- */
- public synchronized List<String> getCustomExcludedPackages() {
- return ImmutableList.copyOf(mCustomPackages);
- }
-
- /**
- * Adds a package to the custom exclusion set and returns true upon success. Success means that
- * the new package was successfully added, and that the new state was committed to disk.
- *
- * <p>This writes to the internal storage.
- *
- * @param packageName the package name
- * @return true on success
- */
- public synchronized boolean addCustom(String packageName) {
- if (mCustomPackages.contains(packageName)) {
- return false;
- }
- List<String> packages = Lists.newArrayList(mCustomPackages);
- packages.add(packageName);
- try {
- writeToFile(packages);
- mCustomPackages.add(packageName);
- return true;
- } catch (IOException e) {
- Log.e(TAG, "Unable to create or update excluded packages file");
- return false;
- }
- }
-
- /**
- * Removes a package from the custom exclusion set.
- *
- * <p>This writes to the internal storage.
- *
- * @param packageName the package name
- * @return whether something was actually removed (for instance, you can't
- * remove a package name that's in {@link #mHardcodedPackages}) and the new state was
- * successfully committed to disk
- */
- public synchronized boolean removeCustom(String packageName) {
- if (!mCustomPackages.contains(packageName)) {
- return false;
- }
- List<String> packages = Lists.newArrayList(mCustomPackages);
- packages.remove(packageName);
- try {
- writeToFile(packages);
- return mCustomPackages.remove(packageName);
- } catch (IOException e) {
- Log.e(TAG, "Unable to modify the excluded packages file");
- return false;
- }
- }
-
- /** Writes {@code packages} to the file. */
- private void writeToFile(List<String> packages) throws IOException {
- FileOutputStream outputStream;
- // We only need to store the custom set of packages. That set is stored as a csv string.
- String output = TextUtils.join(DEMILITER, packages);
- // Create or replace the file. MODE_PRIVATE == Only readable/writable by this app.
- outputStream = mContext.openFileOutput(mStorageFilename, Context.MODE_PRIVATE);
- outputStream.write(output.getBytes());
- outputStream.close();
- }
-
- /**
- * Creates and returns the hardcoded exclusion set.
- */
- private static HashSet<String> getHarcodedPackages() {
- // NOTE(stlafon): Excluding the key guard package might be too coarse, as it makes blind
- // to when the user turns the screen on or off.
- HashSet<String> hardcoded = Sets.newHashSet(
- "com.android.keyguard", // Key guard (screen lock)
- "com.google.android.apps.pixelperfect"); // PixelPerfect
- return hardcoded;
- }
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/PlatformServiceClient.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/PlatformServiceClient.java
deleted file mode 100644
index a42d55c..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/PlatformServiceClient.java
+++ /dev/null
@@ -1,218 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.res.Resources;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.google.android.apps.pixelperfect.util.Clock;
-import com.google.android.apps.pixelperfect.api.IPixelPerfectPlatform;
-import com.google.android.apps.pixelperfect.api.ScreenshotParcel;
-import com.google.common.base.Preconditions;
-import com.google.common.logging.RecordedEvent.Screenshot;
-
-import javax.annotation.Nullable;
-
-/**
- * Client for interacting with PixelPerfectPlatform service.
- */
-public class PlatformServiceClient {
- /**
- * Constructor. Creates a new client object and binds PixelPerfectPlatform
- * service.
- * @param context {@link Context} of the calling application.
- * @param clock {@link Clock} used for time stamps of connection and disconnection times.
- */
- public PlatformServiceClient(Context context, Clock clock) {
- // TODO(mukarram) figure out whether a singleton would suffice.
- // TODO(mukarram) figure out whether we need to synchronize on mPlatformService
- Preconditions.checkNotNull(
- context, "Context must not be null.",
- clock, "Clock must not be null");
- mContext = context;
- mClock = clock;
- initializeTimestamps();
- connectAndBindPlatformService();
- }
-
- /**
- * Obtains a screenshot by making an IPC to the PixelPerfectPlatform service.
- *
- * Note: calling package must be google signed AND white-listed in
- * PixelPerfectPlatform, else a security exception is parceled and thrown
- * while reading the screenshot.
- *
- * @return {@link Screenshot} proto instance that is returned by the
- * PixelPerfectPlatformService. May return null if the returned parcel is as such.
- */
- public @Nullable Screenshot obtainScreenshot() throws RemoteException {
- Log.v(TAG, "Attempting getScreenshot()");
- // TODO(mukarram) Consider adding throttling for screenshots.
- // Also consider whether such throttling makes sense here on the platform service itself.
- ScreenshotParcel parcel = getPlatformServiceIfAvailable().getScreenshot();
- if (parcel == null) {
- return null;
- }
- return parcel.screenshotProto;
- }
-
- private static final String TAG = "PixelPerfect.PlatformServiceClient";
-
- /** Whether we have binding to the platform service. */
- private final Context mContext;
- /** Reference to PixelPerfectPlatform service interface. */
- private IPixelPerfectPlatform mPlatformService = null;
-
- // Following time stamps are used for throttling the re-connection attempts
- // should we loose connection to the service.
- /** Time stamp for when the object is created. */
- private long mLastConnectionAttemptTimeMs = 0;
- /** Time stamp for when we are last connected from the platform service. */
- private long mLastConnectTimeMs = 0;
- /** Time stamp for when we are last disconnected to the platform service. */
- private long mLastDisconnectTimeMs = 0;
- /** Clock used for time stamps.*/
- private Clock mClock = null;
- /** Minimum time (in milliseconds) before attempting a reconnect.*/
- private int mMinTimeMillsecToReconnect = 0;
-
- /**
- * Implements ServiceConnection to PixelPerfectPlatformService. Uses the
- * onServiceConnected() and onServiceDisconnected callbacks to update a
- * reference to PixelPerfectPlatform service interface.
- */
- class PlatformServiceConnection implements ServiceConnection {
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- mPlatformService = IPixelPerfectPlatform.Stub.asInterface(service);
- mLastConnectTimeMs = mClock.nowMs();
- Log.v(TAG, "onServiceConnected: " + className.toString());
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- mPlatformService = null;
- mLastDisconnectTimeMs = mClock.nowMs();
- Log.v(TAG, "onServiceDisconnected " + className.toString());
- }
- }
-
- /** Connection to the PixelPerfectPlatform service. */
- private PlatformServiceConnection mConnection = null;
-
- /**
- * Helper to bind to PixelPerfectPlatform service if not already bound.
- */
- private void bindPlatformService() {
- Log.v(TAG, "Attempting a bind to platform service at: " + mLastConnectionAttemptTimeMs);
- if (mPlatformService != null) {
- Log.v(TAG, "We are already bound to platform service. Do nothing.");
- return;
- }
-
- mContext.bindService(
- // TODO(mukarram) Use explicit intent.
- // We are getting warnings of sort:
- // 02-05 18:07:08.907 W/ContextImpl(16804):
- // Implicit intents with startService are not safe:
- // Intent { act=com.google.android.apps.pixelperfect.api.IPixelPerfectPlatform }
- // android.content.ContextWrapper.bindService:513
- // com.google.android.apps.pixelperfect.
- // PlatformServiceClient.bindPlatformService:51
- // com.google.android.apps.pixelperfect.PlatformServiceClient.<init>:71
- //
- // We tried:
- // Intent intent = new Intent();
- // intent.setClass(mContext, IPixelPerfectPlatform.class);
- // and use that instead of new Intent(IPixelPerfectPlatform.class.getName()),
- // but that did not work out.
- // Still investigating.
- new Intent(IPixelPerfectPlatform.class.getName()),
- mConnection, Context.BIND_AUTO_CREATE);
- }
-
- /**
- * Gets binding to PixelPerfectPlatform service if available. If service was
- * for some reason disconnected, then attempts to reconnect.
- * @return binding to PixelPerfectPlatform service if connected and bound.
- * @throws IllegalStateException if not bound.
- */
- private IPixelPerfectPlatform getPlatformServiceIfAvailable() {
- if (mPlatformService != null) {
- return mPlatformService;
- }
- // We do not have a stub to platform service.
- // See if it is okay to attempt a reconnect, if so fire off a reconnect attempt.
- if (isThrottledConnectionRetryOkay()) {
- Log.v(TAG, "Attempting a reconnect to platform service.");
- // Note: following call does not block for connection to
- // complete, therefore we cannot return a reference to
- // platform service here, so although we are initiating a
- // connection here, we still throw an exception.
- // Recall from above that when connection completes,
- // onServiceConnected() would be called in PlatformServiceConnection
- connectAndBindPlatformService();
- } else {
- Log.v(TAG,
- "Disconnected from platform service, but not ready to reconnect yet."
- + "mLastConnectAttemptMs :" + mLastConnectionAttemptTimeMs
- + " time since:" + (mClock.nowMs() - mLastConnectionAttemptTimeMs));
- }
- // Throw an exception anyway, because we were not ready when get..() was called.
- throw new IllegalStateException(
- "Client not connected to platform service."
- + " Connected at: " + mLastConnectTimeMs
- + " Disconnected at: " + mLastDisconnectTimeMs);
- }
-
- /**
- * Create a connection to PixelPerfectPlatform service if not already
- * connected, and then bind, if not already bound.
- */
- private void connectAndBindPlatformService() {
- // TODO(mukarram) Figure out whether we need to reestablish connection,
- // or whether we can reuse the connection.
- if (mConnection == null) {
- mConnection = new PlatformServiceConnection();
- }
- mLastConnectionAttemptTimeMs = mClock.nowMs();
- bindPlatformService();
- }
-
- private void initializeTimestamps() {
- Resources res = mContext.getResources();
- mMinTimeMillsecToReconnect = res.getInteger(
- R.integer.min_time_ms_between_platform_service_reconnect);
- mLastConnectTimeMs = 0;
- mLastDisconnectTimeMs = 0;
- }
-
- /**
- * Returns true if it is okay to attempt a reconnect. We keep track of
- * time stamps of when connection attempts are made and when connection
- * disconnections occur, and throttle reconnection attempts such that there
- * is at least mMinTimeMillsecToReconnect
- * (R.integer.min_time_ms_between_platform_service_reconnect) is elapsed
- * since last disconnect or between reconnect attempts.
- * @return true if it is okay to retry, false if not.
- */
- private boolean isThrottledConnectionRetryOkay() {
- final long nowMs = mClock.nowMs();
- // If there has been at least one disconnect
- // (i.e., mLastDisconnectTime > 0), then see if enough time has elapsed
- // since last disconnect.
- if (mLastDisconnectTimeMs > 0 &&
- nowMs - mLastDisconnectTimeMs < mMinTimeMillsecToReconnect) {
- return false;
- }
- // See if enough time has elapsed since last connection attempt.
- if (nowMs - mLastConnectionAttemptTimeMs < mMinTimeMillsecToReconnect) {
- return false;
- }
- return true;
- }
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/api/IPixelPerfectPlatform.aidl b/PixelPerfect/src/com/google/android/apps/pixelperfect/api/IPixelPerfectPlatform.aidl
deleted file mode 100644
index 7cf981d..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/api/IPixelPerfectPlatform.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.google.android.apps.pixelperfect.api;
-import com.google.android.apps.pixelperfect.api.ScreenshotParcel;
-
-/**
- * PixelPerfectPlatform service interface. This service allows appropriately
- * authorized packages to obtain certain signals that are only allowed to
- * platform-signed apps. The idea is that the service is implemented in a
- * platform-signed apk.
- */
-interface IPixelPerfectPlatform {
- /**
- * Takes a screenshot
- *
- * @return screenshot {@link ScreenshotParcel} if successful.
- * Exceptions, such as SecurityException if client is not authorized, are parceled back.
- */
- ScreenshotParcel getScreenshot() = 1;
- // TODO(mukarram) Add an interface that allows obtaining clips of a
- // screenshot and controlling whether compression is performed or not.
-}
\ No newline at end of file
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/api/ScreenshotParcel.aidl b/PixelPerfect/src/com/google/android/apps/pixelperfect/api/ScreenshotParcel.aidl
deleted file mode 100644
index 2bcbfeb..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/api/ScreenshotParcel.aidl
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.google.android.apps.pixelperfect.api;
-
-/**
- * Used for IPC to {@link PixelPerfectPlatform} service to obtain screenshots
- * protos {@link Screenshot}.
- */
-parcelable ScreenshotParcel;
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/api/ScreenshotParcel.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/api/ScreenshotParcel.java
deleted file mode 100644
index 831a0b8..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/api/ScreenshotParcel.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.google.android.apps.pixelperfect.api;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.common.logging.RecordedEvent.Screenshot;
-
-import javax.annotation.Nullable;
-
-/**
- * Screenshot parcel. Simply serializes and de-serializes the Screenshot proto
- * to/from the parcel.
- */
-public class ScreenshotParcel implements Parcelable {
- // TODO(mukarram) We we probably want to implement something similar to
- // https://googleplex-android.googlesource.com/platform/vendor/
- // unbundled_google/packages/GoogleSearch/+/ub-now-lunchbox/src/com/google/
- // android/sidekick/shared/remoteapi/ProtoParcelable.java
- public static final Parcelable.Creator<ScreenshotParcel> CREATOR =
- new Parcelable.Creator<ScreenshotParcel>() {
- @Override
- public ScreenshotParcel createFromParcel(Parcel source) {
- return new ScreenshotParcel(source);
- }
-
- @Override
- public ScreenshotParcel[] newArray(int size) {
- return new ScreenshotParcel[size];
- }
- };
-
- private static final String TAG = "PixelPerfectPlatform.ScreenshotParcel";
- private Exception mException = null;
- public Screenshot screenshotProto = null;
-
- public ScreenshotParcel() {
- screenshotProto = null;
- mException = null;
- }
-
- public ScreenshotParcel(Parcel in) {
- readFromParcel(in);
- }
-
- public ScreenshotParcel(Screenshot screenshotProto) {
- this.screenshotProto = screenshotProto;
- }
-
- /**
- * Set the exception that is to be written to parcel.
- * @param e the {@link Exception} to parcel.
- */
- public void setException(@Nullable Exception e) {
- this.mException = e;
- }
-
- // TODO(mukarram) Also add capability to carry any other errors that may
- // occur while capturing screenshots.
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- if (mException != null) {
- out.writeException(mException);
- } else {
- out.writeNoException();
- }
-
- if (screenshotProto == null) {
- out.writeInt(0);
- return;
- }
-
- byte[] bytes = screenshotProto.toByteArray();
- out.writeInt(bytes.length);
- out.writeByteArray(bytes);
- }
-
- public void readFromParcel(Parcel in) {
- in.readException();
- int length = in.readInt();
- byte[] bytes = new byte[length];
- in.readByteArray(bytes);
- try {
- Screenshot.Builder builder = Screenshot.newBuilder();
- builder.mergeFrom(bytes);
- screenshotProto = builder.build();
- } catch (InvalidProtocolBufferException e) {
- Log.e(TAG, "Could not deserialize proto " + e);
- screenshotProto = null;
- }
- }
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PackageArrayAdapter.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PackageArrayAdapter.java
deleted file mode 100644
index 0fd5edc..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PackageArrayAdapter.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package com.google.android.apps.pixelperfect.preferences;
-
-import com.google.android.apps.pixelperfect.R;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Filter;
-import android.widget.Filterable;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/**
- * {@link ArrayAdapter} for displaying and selecting packages. It is used in two contexts:
- * <ul>
- * <li> The autocomplete drop-down used for selecting a package to exclude. In that case, package
- * icon, package name and application name are shown.
- * <li> The custom exclusion list. In that case, the same information as above is shown, plus
- * a button to remove the package from the list of excluded ones.
- * </ul>
- */
-@SuppressLint("DefaultLocale")
-public class PackageArrayAdapter extends ArrayAdapter<PackageItem> implements Filterable {
-
- @SuppressWarnings("unused")
- private static final String TAG = "PixelPerfect.PackageArrayAdapter";
-
- private final List<PackageItem> mAllItems;
- private List<PackageItem> mItems;
-
- /**
- * If true, items are featured in the auto-complete drop-down. Otherwise, it's used in the list
- * of excluded packages.
- */
- private final boolean mForDropDown;
-
- /** Filter that's used for the autocomplete drop-down. */
- private final PackageFilter mFilter;
-
- /** Callback used for removing a package name from the list of excluded packages. */
- private final ReIncludePackageCallback mReIncludePackageCallback;
-
- /**
- * Constructs a {@link PackageArrayAdapter}.
- *
- * @param context the {@link Context}
- * @param resourceId the resource ID for a layout file containing a layout to use when
- * instantiating views
- * @param items the {@link PackageItem}s
- * @param forDropDown if true, this {@link ArrayAdapter} is for the package selection drop-down,
- * otherwise, it's for rendering the list of excluded packages
- * @param reIncludePackageCallback this callback is called when the user wants to
- * remove a given package name from the list of excluded packages. It must be
- * non-{@code null} if and only if {@code forDropDown} is false
- */
- public PackageArrayAdapter(Context context, int resourceId, List<PackageItem> items,
- boolean forDropDown, @Nullable ReIncludePackageCallback reIncludePackageCallback) {
- super(context, resourceId, items);
- // reIncludePackageCallback is null iff forDropDown is true
- Preconditions.checkArgument(forDropDown != (reIncludePackageCallback != null));
- mAllItems = items;
- mForDropDown = forDropDown;
- // Note, the filter is only exercised for the drop-down.
- mFilter = forDropDown ? new PackageFilter() : null;
- // For the drop-down, start with nothing in the list of items. For the list case, start with
- // all the items (and that won't change since filtering never occurs).
- mItems = forDropDown ? null : mAllItems;
- mReIncludePackageCallback = reIncludePackageCallback;
- }
-
- @Override
- public int getCount() {
- return mItems == null ? 0 : mItems.size();
- }
-
- @Override
- public PackageItem getItem(int position) {
- return mItems.get(position);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>Shows the trash button (to remove from the list of excluded packages) if this adapter is
- * used in the list of excluded packages.
- */
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- View row = convertView;
- LayoutInflater inflater = LayoutInflater.from(getContext());
-
- final PackageItem item = getItem(position);
- if (row == null) {
- row = inflater.inflate(R.layout.package_item, parent, false);
- }
-
- TextView applicationNameView = (TextView) row.findViewById(R.id.applicationName);
- TextView packageNameView = (TextView) row.findViewById(R.id.packageName);
- if (item.getApplicationName() != null) {
- applicationNameView.setText(item.getApplicationName());
- }
- packageNameView.setText(item.getPackageName());
- if (item.getIcon() != null) {
- ImageView icon = (ImageView) row.findViewById(R.id.icon);
- icon.setImageDrawable(item.getIcon());
- }
-
- // Don't show the trash button if in the drop-down.
- ImageButton button = (ImageButton) row.findViewById(R.id.button);
- button.setVisibility(mForDropDown ? View.GONE : View.VISIBLE);
- if (!mForDropDown) {
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mReIncludePackageCallback.onReIncludePackage(item.getPackageName());
- }
- });
- }
-
- return row;
- }
-
- @Override
- public Filter getFilter() {
- return mFilter;
- }
-
- /**
- * A {@link Filter} used to autocomplete on the package name.
- */
- private class PackageFilter extends Filter {
-
- /**
- * {@inheritDoc}
- *
- * Filters based on the presence of {@code constraint} as a substring of the package name
- * or the app name.
- */
- @Override
- protected FilterResults performFiltering(CharSequence constraint) {
- FilterResults filterResults = new FilterResults();
- ArrayList<PackageItem> results = Lists.newArrayList();
-
- if (constraint != null) {
- if (mAllItems != null && !mAllItems.isEmpty()) {
- String noramlizedConstraint = PackageItem.getNormalizedString(
- constraint.toString());
- for (PackageItem item : mAllItems) {
- if (item.matches(noramlizedConstraint)) {
- results.add(item);
- }
- }
- }
- filterResults.values = results;
- filterResults.count = results.size();
- }
- return filterResults;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected void publishResults(CharSequence constraint, FilterResults results) {
- mItems = (ArrayList<PackageItem>) results.values;
- notifyDataSetChanged();
- }
- }
-
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PackageItem.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PackageItem.java
deleted file mode 100644
index 9b76612..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PackageItem.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.google.android.apps.pixelperfect.preferences;
-
-import android.graphics.drawable.Drawable;
-
-/**
- * Wrapper for a package name and its associated icon.
- */
-/* package */ class PackageItem {
-
- /** The package name. */
- private final String mPackageName;
-
- /** The application name. Optional. */
- private final String mAppName;
-
- /** The normalized application name. Optional. */
- private final String mNormalizedAppName;
-
- /** The icon. */
- private final Drawable mIcon;
-
- PackageItem(String packageName, String appName, Drawable icon) {
- mPackageName = packageName;
- mAppName = appName;
- mNormalizedAppName = getNormalizedString(appName);
- mIcon = icon;
- }
-
- String getPackageName() {
- return mPackageName;
- }
-
- String getApplicationName() {
- return mAppName;
- }
-
- Drawable getIcon() {
- return mIcon;
- }
-
- /** Normalizes a string for matching. */
- static String getNormalizedString(String input) {
- return input == null ? null : input.trim().toLowerCase();
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>This determines what gets rendered in the autocomplete.
- */
- @Override
- public String toString() {
- return mPackageName;
- }
-
- /**
- * Returns true if {@code normalizedInput} is contained in {@link #mPackageName} or in
- * {@link #mNormalizedAppName}.
- */
- public boolean matches(String normalizedInput) {
- return mPackageName.contains(normalizedInput)
- || (mNormalizedAppName != null && mNormalizedAppName.contains(normalizedInput));
-
- }
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PreferencesActivity.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PreferencesActivity.java
deleted file mode 100644
index e573d4a..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/PreferencesActivity.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.google.android.apps.pixelperfect.preferences;
-
-import com.google.android.apps.pixelperfect.ExcludedPackages;
-import com.google.android.apps.pixelperfect.R;
-import com.google.common.collect.Lists;
-
-import android.app.Activity;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.AutoCompleteTextView;
-import android.widget.ListView;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Preferences class. Allows to pause/resume, and also blacklist certain apps.
- *
- * <p>Users can exclude packages by adding them to the set of excluded packages.
- *
- * <p>NOTE(stlafon): This class is the only one that mutates the set of excluded packages.
- */
-public class PreferencesActivity extends Activity implements ReIncludePackageCallback {
-
- @SuppressWarnings("unused")
- private static final String TAG = "PixelPerfect.PreferencesActivity";
-
- private AutoCompleteTextView mPackageExcludeTextView;
-
- /** Maps a package name to the corresponding {@link PackageItem}. */
- private Map<String, PackageItem> mPackageMap;
-
- /**
- * Instance of {@link ExcludedPackages}. It is the only instance of that class, in the entire
- * application, that mutates the file containing the list of excluded packages.
- */
- private ExcludedPackages mExcludedPackages;
-
- private PackageArrayAdapter mDropDownAdapter;
- private PackageArrayAdapter mExcludedListAdapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.preferences);
-
- // Get the list of all installed packages.
- mExcludedPackages = ExcludedPackages.getInstance(this);
- mPackageMap = getInstalledApplications();
-
- // Take that list, and remove the packages that have already been excluded.
- List<PackageItem> items = Lists.newArrayListWithCapacity(mPackageMap.size());
- items.addAll(mPackageMap.values());
- items.removeAll(getExcludedPackages());
-
- // Populate the autocomplete adapter with that list.
- mDropDownAdapter = new PackageArrayAdapter(this,
- android.R.layout.simple_dropdown_item_1line, items, true, null);
- mPackageExcludeTextView = (AutoCompleteTextView) findViewById(R.id.packageSearch);
- mPackageExcludeTextView.setAdapter(mDropDownAdapter);
-
- // Set up the list of excluded packages.
- ListView excludedList = (ListView) findViewById(R.id.excludedList);
- mExcludedListAdapter = new PackageArrayAdapter(this,
- android.R.layout.simple_list_item_1, getExcludedPackages(), false, this);
- excludedList.setAdapter(mExcludedListAdapter);
- }
-
- /**
- * Called when the "Exclude" button is clicked. Adds the corresponding package name to the set
- * of excluded packages.
- */
- public void onExcludePackage(@SuppressWarnings("unused") View view) {
- String value = PackageItem.getNormalizedString(
- mPackageExcludeTextView.getText().toString());
- if (mPackageMap.containsKey(value)) {
- PackageItem item = mPackageMap.get(value);
- Log.v(TAG, "Excluding " + item);
- // If the package was successfully added to the exclusion list, reflect it in the UI.
- if (mExcludedPackages.addCustom(item.getPackageName())) {
- mExcludedListAdapter.add(item);
- mDropDownAdapter.remove(item);
- mPackageExcludeTextView.setText("");
- }
- }
- }
-
- @Override
- public void onReIncludePackage(String packageName) {
- // If the package was successfully removed from the exclusion list, reflect it in the UI.
- if (mExcludedPackages.removeCustom(packageName)) {
- PackageItem item = getPackageItem(packageName);
- mExcludedListAdapter.remove(item);
- mDropDownAdapter.add(item);
- }
- }
-
- /**
- * Creates and returns a map from installed package names to their corresponding
- * {@link PackageItem}s.
- */
- private Map<String, PackageItem> getInstalledApplications() {
- Map<String, PackageItem> map = new HashMap<String, PackageItem>();
-
- PackageManager pkgManager = getApplicationContext().getPackageManager();
-
- List<ApplicationInfo> appInfo = pkgManager.getInstalledApplications(
- PackageManager.GET_META_DATA);
-
- for (ApplicationInfo info : appInfo) {
- Drawable icon = pkgManager.getApplicationIcon(info);
- String appName = (String) pkgManager.getApplicationLabel(info);
- map.put(info.packageName, new PackageItem(info.packageName, appName, icon));
- }
- return map;
- }
-
- /**
- * Creates and returns the list of excluded packages.
- */
- private List<PackageItem> getExcludedPackages() {
- List<PackageItem> excluded = Lists.newArrayList();
- for (String packageName : mExcludedPackages.getCustomExcludedPackages()) {
- excluded.add(getPackageItem(packageName));
- }
- return excluded;
- }
-
- /**
- * Looks up a {@link PackageItem} for a given package name in the list of installed packages,
- * or returns a new one if it can't be found on this device.
- */
- private PackageItem getPackageItem(String packageName) {
- if (mPackageMap.containsKey(packageName)) {
- return mPackageMap.get(packageName);
- } else {
- // No such package in the list of packages installed on this device. This could happen
- // if the package was un-installed, since we last created the list of installed
- // packages. Or, in the future, if we save the excluded packages in the cloud, this
- // could happen because the package was installed on a different device.
- // In that case, create a new {@code PackageItem}.
- return new PackageItem(packageName, null, null);
- }
- }
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/ReIncludePackageCallback.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/ReIncludePackageCallback.java
deleted file mode 100644
index c976d53..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/preferences/ReIncludePackageCallback.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.google.android.apps.pixelperfect.preferences;
-
-/**
- * Callback used to remove a package name from the list of excluded packages.
- */
-public interface ReIncludePackageCallback {
-
- /**
- * Removes a package name from the list of excluded packages.
- *
- * @param packageName the package name
- */
- void onReIncludePackage(String packageName);
-
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/util/Clock.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/util/Clock.java
deleted file mode 100644
index b7a9f94..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/util/Clock.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.google.android.apps.pixelperfect.util;
-
-/**
- * Provides current value of time (now).
- */
-public interface Clock {
- /**
- * Returns the current, absolute time in milliseconds, according to this clock.
- */
- public long nowMs();
-}
diff --git a/PixelPerfect/src/com/google/android/apps/pixelperfect/util/RealClock.java b/PixelPerfect/src/com/google/android/apps/pixelperfect/util/RealClock.java
deleted file mode 100644
index 2e13833..0000000
--- a/PixelPerfect/src/com/google/android/apps/pixelperfect/util/RealClock.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.google.android.apps.pixelperfect.util;
-
-import android.os.SystemClock;
-
-/**
- * Implements {@link Clock} and provides nowMs according to SystemClock.
- */
-public class RealClock implements Clock {
- @Override
- public long nowMs() {
- return SystemClock.elapsedRealtime();
- }
-}
\ No newline at end of file
diff --git a/PixelPerfect/tests/Android.mk b/PixelPerfect/tests/Android.mk
index 42231b5..aba4904 100644
--- a/PixelPerfect/tests/Android.mk
+++ b/PixelPerfect/tests/Android.mk
@@ -1,28 +1,21 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target \
+ android-support-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_CERTIFICATE := platform
-# Use Google certificate instead of platform certificate since GmsCore
-# only allows usage from apps signed with the Google certificate.
-# Note: the cert here and in ../Android.mk should match.
-LOCAL_CERTIFICATE := vendor/unbundled_google/libraries/certs/app
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
-# Include all test java files.
-api_source_file_patterns = src/com/google/android/apps/pixelperfect/api/%
-platform_source_file_patterns = src/com/google/android/apps/pixelperfect/platform/%
-LOCAL_SRC_FILES := $(filter-out $(api_source_file_patterns), \
- $(filter-out $(platform_source_file_patterns), $(call all-java-files-under, src)))
+LOCAL_PACKAGE_NAME := PixelPerfectPlatformTests
-LOCAL_PACKAGE_NAME := PixelPerfectTests
+LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_INSTRUMENTATION_FOR := PixelPerfect
+LOCAL_INSTRUMENTATION_FOR := PixelPerfectPlatform
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 10
include $(BUILD_PACKAGE)
diff --git a/PixelPerfect/tests/AndroidManifest.xml b/PixelPerfect/tests/AndroidManifest.xml
index fc9a358..cc47425 100644
--- a/PixelPerfect/tests/AndroidManifest.xml
+++ b/PixelPerfect/tests/AndroidManifest.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.apps.pixelperfect.tests">
+ package="com.google.android.apps.pixelperfect.platform.tests">
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
@@ -13,10 +13,10 @@
<!--
This declares that this app uses the instrumentation test runner targeting
the package of com.example.android.apis. To run the tests use the command:
- "adb shell am instrument -w com.example.android.apis.tests/android.test.InstrumentationTestRunner"
+ "adb shell am instrument -w com.google.android.apps.pixelperfect.platform.tests/android.test.InstrumentationTestRunner"
-->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.google.android.apps.pixelperfect"
- android:label="Tests for PixelPerfect."/>
+ android:targetPackage="com.google.android.apps.pixelperfect.platform"
+ android:label="Tests for PixelPerfectPlatform."/>
</manifest>
diff --git a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/AccessibilityEventProcessorTest.java b/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/AccessibilityEventProcessorTest.java
deleted file mode 100644
index 594ccaa..0000000
--- a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/AccessibilityEventProcessorTest.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.when;
-
-import android.annotation.TargetApi;
-import android.graphics.Rect;
-import android.os.Build;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.google.android.apps.pixelperfect.AccessibilityEventProcessor.ClearcutLogger;
-import com.google.common.logging.RecordedEvent;
-import com.google.common.logging.RecordedEvent.RecordedTypes.WidgetType;
-import com.google.common.logging.RecordedEvent.UIElement;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.List;
-
-/**
- * Tests for {@link AccessibilityEventProcessor}.
- */
-@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
-@SmallTest
-public class AccessibilityEventProcessorTest extends AndroidTestCase {
-
- private static final String VIEW_ID_RESOURCE_NAME_1 = "view 1";
- private static final String TEXT_1 = "text 1";
- private static final String TEXT_2 = "text 2";
- private static final String TEXT_3 = "text 3";
- private static final String WIDGET_CLASS_NAME_1 = "android.widget.CheckedTextView";
- private static final String WIDGET_CLASS_NAME_2 = "android.widget.LinearLayout";
- private static final String WIDGET_CLASS_NAME_3 = "android.widget.EditText";
- private static final String WIDGET_CLASS_NAME_4 = "android.widget.EditText";
-
- private static final Rect RECT = new Rect(110, 120, 130, 140);
- private static final Rect RECT_B = new Rect(210, 220, 230, 240);
- private static final Rect RECT_C = new Rect(310, 320, 330, 340);
-
- @Mock private AccessibilityNodeInfo mNode;
- @Mock private AccessibilityNodeInfo mSubNodeA;
- @Mock private AccessibilityNodeInfo mSubNodeB;
- @Mock private AccessibilityNodeInfo mSubNodeC;
-
- @Mock private ExcludedPackages mExcludedPackages;
- @Mock private ClearcutLogger mLogger;
-
- private AccessibilityEventProcessor mProcessor;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- // The following is needed to make mockito work.
- // see https://code.google.com/p/dexmaker/issues/detail?id=2
- System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
- MockitoAnnotations.initMocks(this);
- mProcessor = new AccessibilityEventProcessor(mExcludedPackages, null, mLogger);
- }
-
- public void testCreateUIElement() {
- // Stubbing for the top node.
- when(mNode.getClassName()).thenReturn(WIDGET_CLASS_NAME_1);
- when(mNode.getViewIdResourceName()).thenReturn(VIEW_ID_RESOURCE_NAME_1);
- when(mNode.getText()).thenReturn(TEXT_1);
- when(mNode.getChildCount()).thenReturn(3);
- doAnswer(new Answer<Object>() {
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Rect rect = (Rect) invocation.getArguments()[0];
- rect.set(RECT);
- return null;
- }
- }).when(mNode).getBoundsInParent(isA(Rect.class));
-
- // Stubbing for subnode A.
- when(mSubNodeA.getClassName()).thenReturn(WIDGET_CLASS_NAME_2);
- when(mSubNodeA.getViewIdResourceName()).thenReturn(null);
- when(mSubNodeA.getText()).thenReturn(TEXT_2);
- when(mSubNodeA.getChildCount()).thenReturn(0);
- when(mNode.getChild(0)).thenReturn(mSubNodeA);
-
- // Stubbing for subnode B.
- when(mSubNodeB.getClassName()).thenReturn(WIDGET_CLASS_NAME_3);
- when(mSubNodeB.getViewIdResourceName()).thenReturn(null);
- when(mSubNodeB.getText()).thenReturn(null);
- when(mSubNodeB.getChildCount()).thenReturn(0);
- doAnswer(new Answer<Object>() {
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Rect rect = (Rect) invocation.getArguments()[0];
- rect.set(RECT_B);
- return null;
- }
- }).when(mSubNodeB).getBoundsInParent(isA(Rect.class));
- when(mNode.getChild(1)).thenReturn(mSubNodeB);
-
- // Stubbing for subnode C, which in this case is a password node.
- when(mSubNodeC.getClassName()).thenReturn(WIDGET_CLASS_NAME_4);
- when(mSubNodeC.getViewIdResourceName()).thenReturn(null);
- when(mSubNodeC.getText()).thenReturn(TEXT_3);
- when(mSubNodeC.isPassword()).thenReturn(true);
- when(mSubNodeC.getChildCount()).thenReturn(0);
- doAnswer(new Answer<Object>() {
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Rect rect = (Rect) invocation.getArguments()[0];
- rect.set(RECT_C);
- return null;
- }
- }).when(mSubNodeC).getBoundsInParent(isA(Rect.class));
- when(mNode.getChild(2)).thenReturn(mSubNodeC);
-
- // Run the test.
- // TODO(mukarram) add test for Screenshots being set properly.
- UIElement element = mProcessor.createUIElement(mNode, null, true);
-
- checkElement(element, WidgetType.CHECKED_TEXT_VIEW, VIEW_ID_RESOURCE_NAME_1, TEXT_1, false, RECT);
-
- List<UIElement> childList = element.getChildList();
- assertEquals(3, childList.size());
- checkElement(childList.get(0), WidgetType.LINEAR_LAYOUT, null, TEXT_2, false, new Rect());
- checkElement(childList.get(1), WidgetType.EDIT_TEXT, null, null, false, RECT_B);
- // For the third child, we expect content to be elided.
- checkElement(childList.get(2), WidgetType.EDIT_TEXT, null, null, true, RECT_C);
- }
-
- public void testShouldElideContent() {
- when(mNode.isPassword()).thenReturn(true);
- assertTrue(mProcessor.shouldElideContent(mNode));
-
- when(mNode.isPassword()).thenReturn(false);
- assertFalse(mProcessor.shouldElideContent(mNode));
- }
-
- private void checkElement(UIElement element, WidgetType classType, String resourceName,
- String content, boolean contentElided, Rect rect) {
- assertEquals(classType, element.getClassType());
- if (resourceName != null) {
- assertEquals(resourceName, element.getResourceName());
- } else {
- assertFalse(element.hasResourceName());
- }
- if (content != null) {
- assertEquals(content, element.getContent());
- } else {
- assertFalse(element.hasContent());
- }
- assertEquals(contentElided, element.getContentElided());
- checkRect(rect, element.getRect());
- }
-
- private void checkRect(Rect rect, RecordedEvent.RecordedRect recordedRect) {
- assertEquals(rect.left, recordedRect.getLeft());
- assertEquals(rect.top, recordedRect.getTop());
- assertEquals(rect.right, recordedRect.getRight());
- assertEquals(rect.bottom, recordedRect.getBottom());
- }
-
-}
diff --git a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/AccessibilityEventServiceTest.java b/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/AccessibilityEventServiceTest.java
deleted file mode 100644
index efe41a6..0000000
--- a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/AccessibilityEventServiceTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import android.accounts.Account;
-import android.annotation.TargetApi;
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.content.Intent;
-import android.test.ServiceTestCase;
-
-/**
- * Tests for {@link AccessibilityEventService}.
- */
-public class AccessibilityEventServiceTest extends ServiceTestCase<AccessibilityEventService> {
-
- private static final String ACCOUNT_NAME = "stlafon@google.com";
-
- public AccessibilityEventServiceTest() {
- super(AccessibilityEventService.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- startService(new Intent(getContext(), AccessibilityEventService.class));
- }
-
- public void testPauseAndResume() {
- assertFalse(getService().getIsPaused());
-
- Intent intent = new Intent(getService(), AccessibilityEventService.class)
- .setAction(AccessibilityEventService.ACTION_PAUSE);
- startService(intent);
- assertTrue(getService().getIsPaused());
-
- intent = new Intent(getContext(), AccessibilityEventService.class); // No action
- startService(intent);
- assertTrue(getService().getIsPaused());
-
- intent = new Intent(getContext(), AccessibilityEventService.class)
- .setAction(AccessibilityEventService.ACTION_RESUME);
- startService(intent);
- assertFalse(getService().getIsPaused());
- }
-
- @TargetApi(19) // for Notification#actions
- public void testCreateNotification() {
- // This test is pretty limited because it's not possible to look at the Intent inside a
- // PendingIntent.
- Notification notification = getService().createNotification(false);
- Action[] actions = notification.actions;
- assertEquals(2, actions.length);
- }
-
- public void testGetCorpAccountNameImpl() {
- Account googleCorp = new Account(ACCOUNT_NAME, "com.google");
- Account gmail = new Account("foo@gmail.com", "com.gmail");
-
- Account[] accountsNoCorp = { gmail };
- assertNull(getService().getAccountNameImpl(accountsNoCorp));
-
- Account[] accountsHasCorp = { googleCorp, gmail };
- assertEquals(ACCOUNT_NAME, getService().getAccountNameImpl(accountsHasCorp));
- }
-}
diff --git a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/ExcludedPackagesTest.java b/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/ExcludedPackagesTest.java
deleted file mode 100644
index 4237ac3..0000000
--- a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/ExcludedPackagesTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.google.android.apps.pixelperfect;
-
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Tests for {@link ExcludedPackages}.
- */
-@SmallTest
-public class ExcludedPackagesTest extends AndroidTestCase {
-
- private static final String GMAIL = "com.google.gmail";
- private static final String MAPS = "com.google.maps";
- private static final String NOW = "com.google.now";
- private static final String YOUTUBE = "com.google.youtube";
-
- private static final Set<String> HARDCODED_PACKAGES = new HashSet<String>();
- static {
- HARDCODED_PACKAGES.add(GMAIL);
- HARDCODED_PACKAGES.add(NOW);
- }
-
- private static final String FILENAME = "excluded_packages_tests.csv";
-
- private ExcludedPackages mExcludedPackages;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- cleanUpStorageFile();
- mExcludedPackages = getNewInstance();
- }
-
- @Override
- protected void tearDown() throws Exception {
- cleanUpStorageFile();
- }
-
- public void testExclusion() {
- assertExcluded(GMAIL);
- assertExcluded(NOW);
- assertNotExcluded("com.google.gmail2");
- assertNotExcluded("com.ggggggle.now");
- assertNotExcluded(YOUTUBE);
-
- assertTrue(mExcludedPackages.addCustom(YOUTUBE));
- assertExcluded(YOUTUBE);
-
- assertTrue(mExcludedPackages.removeCustom(YOUTUBE));
- assertNotExcluded(YOUTUBE);
-
- assertFalse(mExcludedPackages.removeCustom(GMAIL));
- }
-
- public void testReadFile() throws Exception {
- FileOutputStream outputStream;
- String output = MAPS + "," + YOUTUBE;
- outputStream = mContext.openFileOutput(FILENAME, Context.MODE_PRIVATE);
- outputStream.write(output.getBytes());
- outputStream.close();
-
- mExcludedPackages = getNewInstance();
- MoreAsserts.assertContentsInAnyOrder(mExcludedPackages.getCustomExcludedPackages(),
- MAPS, YOUTUBE);
- }
-
- private void assertExcluded(String packageName) {
- assertTrue(mExcludedPackages.isExcluded(packageName));
- }
-
- private void assertNotExcluded(String packageName) {
- assertTrue(!mExcludedPackages.isExcluded(packageName));
- }
-
- private void cleanUpStorageFile() throws Exception {
- File dir = mContext.getFilesDir();
- File file = new File(dir, FILENAME);
- file.delete();
- }
-
- private ExcludedPackages getNewInstance() {
- return new ExcludedPackages(HARDCODED_PACKAGES, getContext(), FILENAME);
- }
-}
diff --git a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/PlatformServiceClientTest.java b/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/PlatformServiceClientTest.java
deleted file mode 100644
index 414c46a..0000000
--- a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/PlatformServiceClientTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.google.android.apps.pixelperfect;
-import android.test.AndroidTestCase;
-
-import com.google.android.apps.pixelperfect.testutil.FakeClock;
-
-/**
- * Tests for PlatformServiceClient
- * TODO(mukarram) Do something meaningful here.
- */
-public class PlatformServiceClientTest extends AndroidTestCase {
- public PlatformServiceClientTest() {
- // TODO(mukarram): Auto-generated constructor stub
- }
-}
diff --git a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/api/ScreenshotParcelTest.java b/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/api/ScreenshotParcelTest.java
deleted file mode 100644
index ba07350..0000000
--- a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/api/ScreenshotParcelTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.google.android.apps.pixelperfect.api;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.google.android.apps.pixelperfect.platform.ScreenshotGrabber;
-import com.google.common.logging.RecordedEvent;
-import com.google.common.logging.RecordedEvent.Screenshot;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayOutputStream;
-
-/**
- * Tests for {@link ScreenshotParcel}.
- */
-@SmallTest
-public class ScreenshotParcelTest extends TestCase {
- private Screenshot mScreenshotProto = null;
- private Parcel mParcel = null;
-
- private void createTestScreenshotProto() throws Exception {
- final int height = 10;
- final int width = 15;
- final int rotation = 100;
- final int quality = 50;
- final byte[] compressed_bytes = new byte[] {
- (byte) 0xca, (byte) 0xfe };
-
- ByteArrayOutputStream output = new ByteArrayOutputStream(
- compressed_bytes.length);
- output.write(compressed_bytes, 0, compressed_bytes.length);
- ScreenshotGrabber grabber = new ScreenshotGrabber();
- mScreenshotProto = grabber.fillScreenshotProto(
- output, height, width, rotation,
- RecordedEvent.Bitmap.BitmapConfig.Config.ARGB_8888,
- RecordedEvent.Bitmap.CompressionConfig.CompressFormat.JPEG,
- quality);
-
- // TODO(mukarram) figure out why ScreenshotParcel(mScreenshotProto)
- // does not work.
- ScreenshotParcel screenshotParcel = new ScreenshotParcel();
- screenshotParcel.screenshotProto = mScreenshotProto;
-
- Bundle bundle = new Bundle();
- bundle.putParcelable("screenshotParcel", screenshotParcel);
- mParcel = Parcel.obtain();
- bundle.writeToParcel(mParcel, 0);
- }
-
- public static void assertProtosEqual(Screenshot protoA, Screenshot protoB) {
- assertEquals(protoA.getRotation(), protoB.getRotation());
- assertEquals(protoA.getBitmap().getBitmap(), protoB.getBitmap().getBitmap());
- assertEquals(protoA.getBitmap().getHeight(), protoB.getBitmap().getHeight());
- assertEquals(protoA.getBitmap().getWidth(), protoB.getBitmap().getWidth());
- assertEquals(protoA.getRotation(), protoB.getRotation());
-
- assertEquals(protoA.getBitmap().getBitmapConfig().getValue(),
- protoB.getBitmap().getBitmapConfig().getValue());
- assertEquals(protoA.getBitmap().getCompressionConfig().getFormat(),
- protoB.getBitmap().getCompressionConfig().getFormat());
- assertEquals(protoA.getBitmap().getCompressionConfig().getQuality(),
- protoB.getBitmap().getCompressionConfig().getQuality());
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- createTestScreenshotProto();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- if (mParcel != null) {
- mParcel.recycle();
- }
- }
-
- public void testParcelReadWrite() {
- mParcel.setDataPosition(0);
- Bundle testBundle = mParcel.readBundle();
- testBundle.setClassLoader(ScreenshotParcelTest.class.getClassLoader());
- ScreenshotParcel testScreenshotParcel = testBundle.getParcelable("screenshotParcel");
- assertProtosEqual(mScreenshotProto, testScreenshotParcel.screenshotProto);
- }
-
-}
diff --git a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/testutil/FakeClock.java b/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/testutil/FakeClock.java
deleted file mode 100644
index 0eb761f..0000000
--- a/PixelPerfect/tests/src/com/google/android/apps/pixelperfect/testutil/FakeClock.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.google.android.apps.pixelperfect.testutil;
-
-import com.google.android.apps.pixelperfect.util.Clock;
-
-/**
- * A fake clock that implements {@link Clock} interface. Use for tests.
- */
-public class FakeClock implements Clock {
- @Override
- public long nowMs() {
- return nowMs;
- }
- /** Set current time*/
- public void setTime(long nowMs) {
- this.nowMs = nowMs;
- }
- /** Advance current time*/
- public void advanceTime(long diffMs) {
- nowMs += diffMs;
- }
- private long nowMs = 0;
-}