ResearchLog splash screen

Bug: 6188932
Change-Id: I1b247ecc26a2dd4f3f1c1b1cd3d928af717ebdd5
diff --git a/java/res/layout/research_splash.xml b/java/res/layout/research_splash.xml
new file mode 100644
index 0000000..56fd702
--- /dev/null
+++ b/java/res/layout/research_splash.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:id="@+id/research_splash_screen_layout">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <com.android.internal.widget.DialogTitle
+            style="?android:attr/windowTitleStyle"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_width="match_parent"
+            android:layout_height="64dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
+            android:gravity="center_vertical|left"
+            android:text="@string/research_splash_title" />
+        <View android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:background="@android:color/holo_blue_light" />
+    </LinearLayout>
+
+    <TextView
+        android:text="@string/research_splash_content"
+        android:layout_height="fill_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="fill_horizontal|center_vertical"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:layout_marginBottom="16dip"
+        android:layout_marginTop="16dip"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:divider="?android:attr/dividerHorizontal"
+        android:showDividers="beginning"
+        android:dividerPadding="0dip">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:measureWithLargestChild="true">
+            <Button
+                android:layout_width="0dip"
+                android:layout_gravity="left"
+                android:layout_weight="1"
+                android:maxLines="2"
+                stype="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:text="@string/research_dont_send_usage_info"
+                android:layout_height="wrap_content"
+                android:id="@+id/research_do_not_log_button" />
+            <Button
+                android:layout_width="0dip"
+                android:layout_gravity="right"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:text="@string/research_send_usage_info"
+                android:layout_height="wrap_content"
+                android:id="@+id/research_do_log_button" />
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 377018a..12abf84 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -263,6 +263,19 @@
     <!-- TODO: remove translatable=false attribute once text is stable -->
     <string name="research_please_exit_feedback_form" translatable="false">Please exit the feedback dialog to access the research log menu</string>
 
+    <!-- Title of dialog shown at start informing users about contributing research usage data-->
+    <!-- TODO: remove translatable=false attribute once text is stable -->
+    <string name="research_splash_title" translatable="false">Usage Participation</string>
+    <!-- Contents of note explaining what data is collected and how. -->
+    <!-- TODO: remove translatable=false attribute once text is stable -->
+    <string name="research_splash_content" translatable="false">Thank you for dogfooding this keyboard.\n\nIf you like it, please help us make it better by sending us usage information.  When enabled, the keyboard uploads general statistics, such as how fast you type, and also occasional samples of how you type words.\n\nNo passwords or non-dictionary words are ever automatically uploaded, and words are sampled infrequently enough so that reconstructing the meaning of what you typed is highly unlikely.\n\nYou can disable and reenable logging through the RLog menu by long-pressing on the microphone or settings key.\n</string>
+    <!-- Button label text for opting out of research usage data collection [CHAR LIMIT=50] -->
+    <!-- TODO: remove translatable=false attribute once text is stable -->
+    <string name="research_dont_send_usage_info" translatable="false">Do not send\nusage info</string>
+    <!-- Button label text for opting into research usage data collection [CHAR LIMIT=50] -->
+    <!-- TODO: remove translatable=false attribute once text is stable -->
+    <string name="research_send_usage_info" translatable="false">Send usage info</string>
+
     <!-- Preference for input language selection -->
     <string name="select_language">Input languages</string>
 
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index cf19663..0a7e7a2 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -509,6 +509,17 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // Notify the research logger that the keyboard view has been attached.  This is needed
+        // to properly show the splash screen, which requires that the window token of the
+        // KeyboardView be non-null.
+        if (ProductionFlag.IS_EXPERIMENTAL) {
+            ResearchLogger.getInstance().latinKeyboardView_onAttachedToWindow();
+        }
+    }
+
+    @Override
     public void cancelAllMessages() {
         mKeyTimerHandler.cancelAllMessages();
         super.cancelAllMessages();
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index e6828da..a4234a9 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -19,27 +19,36 @@
 import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
 
 import android.app.AlertDialog;
+import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.inputmethodservice.InputMethodService;
 import android.os.Build;
+import android.os.IBinder;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.Window;
+import android.view.WindowManager;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.widget.Button;
 import android.widget.Toast;
 
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardId;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.keyboard.LatinKeyboardView;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.R;
@@ -73,6 +82,7 @@
     /* package */ static boolean sIsLogging = false;
     private static final int OUTPUT_FORMAT_VERSION = 1;
     private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
+    private static final String PREF_RESEARCH_HAS_SEEN_SPLASH = "pref_research_has_seen_splash";
     /* package */ static final String FILENAME_PREFIX = "researchLog";
     private static final String FILENAME_SUFFIX = ".txt";
     private static final SimpleDateFormat TIMESTAMP_DATEFORMAT =
@@ -118,7 +128,7 @@
     private Suggest mSuggest;
     private Dictionary mDictionary;
     private KeyboardSwitcher mKeyboardSwitcher;
-    private Context mContext;
+    private InputMethodService mInputMethodService;
 
     private ResearchLogUploader mResearchLogUploader;
 
@@ -163,11 +173,8 @@
         mResearchLogUploader = new ResearchLogUploader(ims, mFilesDir);
         mResearchLogUploader.start();
         mKeyboardSwitcher = keyboardSwitcher;
-        mContext = ims;
+        mInputMethodService = ims;
         mPrefs = prefs;
-
-        // TODO: force user to decide at splash screen instead of defaulting to on.
-        setLoggingAllowed(true);
     }
 
     private void cleanupLoggingDir(final File dir, final long time) {
@@ -179,6 +186,73 @@
         }
     }
 
+    public void latinKeyboardView_onAttachedToWindow() {
+        maybeShowSplashScreen();
+    }
+
+    private boolean hasSeenSplash() {
+        return mPrefs.getBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, false);
+    }
+
+    private Dialog mSplashDialog = null;
+
+    private void maybeShowSplashScreen() {
+        if (hasSeenSplash()) {
+            return;
+        }
+        if (mSplashDialog != null && mSplashDialog.isShowing()) {
+            return;
+        }
+        final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
+        if (windowToken == null) {
+            return;
+        }
+        mSplashDialog = new Dialog(mInputMethodService, android.R.style.Theme_Holo_Dialog);
+        mSplashDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        mSplashDialog.setContentView(R.layout.research_splash);
+        mSplashDialog.setCancelable(true);
+        final Window w = mSplashDialog.getWindow();
+        final WindowManager.LayoutParams lp = w.getAttributes();
+        lp.token = windowToken;
+        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+        w.setAttributes(lp);
+        w.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+        mSplashDialog.setOnCancelListener(new OnCancelListener() {
+            @Override
+            public void onCancel(DialogInterface dialog) {
+                mInputMethodService.requestHideSelf(0);
+            }
+        });
+        final Button doNotLogButton = (Button) mSplashDialog.findViewById(
+                R.id.research_do_not_log_button);
+        doNotLogButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onUserLoggingElection(false);
+                mSplashDialog.dismiss();
+            }
+        });
+        final Button doLogButton = (Button) mSplashDialog.findViewById(R.id.research_do_log_button);
+        doLogButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onUserLoggingElection(true);
+                mSplashDialog.dismiss();
+            }
+        });
+        mSplashDialog.show();
+    }
+
+    public void onUserLoggingElection(final boolean enableLogging) {
+        setLoggingAllowed(enableLogging);
+        if (mPrefs == null) {
+            return;
+        }
+        final Editor e = mPrefs.edit();
+        e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true);
+        e.apply();
+    }
+
     private File createLogFile(File filesDir) {
         final StringBuilder sb = new StringBuilder();
         sb.append(FILENAME_PREFIX).append('-');
@@ -189,6 +263,7 @@
     }
 
     private void start() {
+        maybeShowSplashScreen();
         updateSuspendedState();
         requestIndicatorRedraw();
         if (!isAllowedToLog()) {
@@ -705,7 +780,7 @@
         }
         researchLogger.start();
         if (editorInfo != null) {
-            final Context context = researchLogger.mContext;
+            final Context context = researchLogger.mInputMethodService;
             try {
                 final PackageInfo packageInfo;
                 packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),
@@ -900,7 +975,7 @@
             // Play it safe.  Remove privacy-sensitive events.
             researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true);
             researchLogger.mCurrentLogUnit = new LogUnit();
-            getInstance().restart();
+            getInstance().stop();
         }
     }