am 262b1e75: Merge "Remove researcher logger"
* commit '262b1e75182ecd34e7488c6ac98341c45dc9f24d': Remove researcher loggermain
commit
08af47cb03
|
@ -1,31 +0,0 @@
|
||||||
<?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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<com.android.inputmethod.research.FeedbackLayout
|
|
||||||
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_feedback_layout"
|
|
||||||
>
|
|
||||||
|
|
||||||
<fragment
|
|
||||||
android:id="@+id/research_feedback_fragment"
|
|
||||||
android:name="com.android.inputmethod.research.FeedbackFragment"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
/>
|
|
||||||
</com.android.inputmethod.research.FeedbackLayout>
|
|
|
@ -1,115 +0,0 @@
|
||||||
<?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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- Adapted from frameworks/base/core/res/res/layout/alert_dialog_holo.xml. We
|
|
||||||
want a dialog, but it must be its own activity so we can launch the soft
|
|
||||||
keyboard on it. A regular dialog will not work since it would be launched from
|
|
||||||
the IME. -->
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dip"
|
|
||||||
android:layout_marginEnd="8dip"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<View android:layout_width="match_parent"
|
|
||||||
android:layout_height="2dip"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:background="@android:color/holo_blue_light" />
|
|
||||||
<TextView
|
|
||||||
style="?android:attr/windowTitleStyle"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="64dip"
|
|
||||||
android:layout_marginLeft="16dip"
|
|
||||||
android:layout_marginRight="16dip"
|
|
||||||
android:gravity="center_vertical|left"
|
|
||||||
android:text="@string/research_feedback_dialog_title" />
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="2dip"
|
|
||||||
android:background="@android:color/holo_blue_light" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/research_feedback_contents"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_gravity="fill_horizontal|center_vertical"
|
|
||||||
android:layout_marginLeft="8dip"
|
|
||||||
android:layout_marginRight="8dip"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:layout_marginTop="8dip"
|
|
||||||
android:minLines="2"
|
|
||||||
android:scrollbars="vertical"
|
|
||||||
android:hint="@string/research_feedback_hint"
|
|
||||||
android:inputType="textMultiLine|textCapSentences">
|
|
||||||
<requestFocus />
|
|
||||||
</EditText>
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/research_feedback_include_account_name"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_marginLeft="16dip"
|
|
||||||
android:layout_marginRight="16dip"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:checked="false"
|
|
||||||
android:text="@string/research_feedback_include_account_name_label" />
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/research_feedback_include_recording_checkbox"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_marginLeft="16dip"
|
|
||||||
android:layout_marginRight="16dip"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:checked="false"
|
|
||||||
android:text="@string/research_feedback_include_recording_label" />
|
|
||||||
<LinearLayout
|
|
||||||
style="?android:attr/buttonBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layoutDirection="locale"
|
|
||||||
android:measureWithLargestChild="true">
|
|
||||||
<Button
|
|
||||||
android:id="@+id/research_feedback_cancel_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_gravity="left"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:maxLines="2"
|
|
||||||
style="?android:attr/buttonBarButtonStyle"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:text="@string/research_feedback_cancel"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<Button
|
|
||||||
android:id="@+id/research_feedback_send_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:maxLines="2"
|
|
||||||
style="?android:attr/buttonBarButtonStyle"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:text="@string/research_feedback_send"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?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="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/research_feedback_contents"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_gravity="fill_horizontal|center_vertical"
|
|
||||||
android:layout_marginLeft="8dip"
|
|
||||||
android:layout_marginRight="8dip"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:layout_marginTop="8dip"
|
|
||||||
android:lines="2"
|
|
||||||
android:hint="@string/research_feedback_hint"
|
|
||||||
android:inputType="textMultiLine"
|
|
||||||
android:imeOptions="flagNoFullscreen"
|
|
||||||
android:focusable="true"
|
|
||||||
>
|
|
||||||
<requestFocus />
|
|
||||||
</EditText>
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/research_feedback_include_history"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:checked="true"
|
|
||||||
android:text="@string/research_feedback_include_history_label"
|
|
||||||
/>
|
|
||||||
</LinearLayout>
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropsies"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropsies"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Navorsing-loglêerbevele"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Soek kontakname op"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Soek kontakname op"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Speltoetser gebruik inskrywings uit jou kontaklys"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Speltoetser gebruik inskrywings uit jou kontaklys"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreer met sleuteldruk"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreer met sleuteldruk"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"ግቤት አማራጮች"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"ግቤት አማራጮች"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"የጥናት የምዝግብ ማስታወሻ ትዕዛዞች"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"የእውቅያ ስሞችን ተመልከት"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"የእውቅያ ስሞችን ተመልከት"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"ፊደል አራሚ ከእውቅያ ዝርዝርህ የገቡትን ይጠቀማል"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"ፊደል አራሚ ከእውቅያ ዝርዝርህ የገቡትን ይጠቀማል"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"በቁልፍመጫንጊዜ አንዝር"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"በቁልፍመጫንጊዜ አንዝር"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"خيارات الإرسال"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"خيارات الإرسال"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"أوامر سجلات البحث"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"بحث في أسماء جهات الاتصال"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"بحث في أسماء جهات الاتصال"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"يستخدم المدقق الإملائي إدخالات من قائمة جهات الاتصال"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"يستخدم المدقق الإملائي إدخالات من قائمة جهات الاتصال"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"اهتزاز عند ضغط مفتاح"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"اهتزاز عند ضغط مفتاح"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Daxiletmə seçimləri"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Daxiletmə seçimləri"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Araşdırma Jurnalı Əmrləri"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakt adlarına baxın"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakt adlarına baxın"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Orfoqrafik yoxlanış kontakt siyahınızdakı qeydlərdən istifadə edir"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Orfoqrafik yoxlanış kontakt siyahınızdakı qeydlərdən istifadə edir"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrasiyalı klikləmə"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrasiyalı klikləmə"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Опции за въвеждане"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Опции за въвеждане"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Команди за рег. файл за проучвания"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Търсене на имена"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Търсене на имена"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"За проверка на правописа се ползват записи от списъка с контакти"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"За проверка на правописа се ползват записи от списъка с контакти"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Да вибрира при натискане на клавиш"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Да вибрира при натискане на клавиш"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opcions d\'entrada"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opcions d\'entrada"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Recerca d\'ordres de reg."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca noms de contactes"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca noms de contactes"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortogràfic utilitza entrades de la llista de contactes"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortogràfic utilitza entrades de la llista de contactes"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibra en prémer tecles"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibra en prémer tecles"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávání textu a dat"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávání textu a dat"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Příkazy vývoj. protokolu"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhledat kontakty"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhledat kontakty"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kontrola pravopisu používá záznamy z vašeho seznamu kontaktů."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kontrola pravopisu používá záznamy z vašeho seznamu kontaktů."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Při stisku klávesy vibrovat"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Při stisku klávesy vibrovat"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Indstillinger for input"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Indstillinger for input"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Forskningslogkommandoer"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Anvend kontaktnavne"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Anvend kontaktnavne"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruger ord fra dine kontaktpersondata"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruger ord fra dine kontaktpersondata"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibration ved tastetryk"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibration ved tastetryk"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Eingabeoptionen"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Eingabeoptionen"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Forschungsprotokollbefehle"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktnamen prüfen"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktnamen prüfen"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Rechtschreibprüfung kann Einträge aus meiner Kontaktliste verwenden"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Rechtschreibprüfung kann Einträge aus meiner Kontaktliste verwenden"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Bei Tastendruck vibrieren"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Bei Tastendruck vibrieren"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Επιλογές εισόδου"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Επιλογές εισόδου"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Έρευνα εντολών καταγραφής"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Αναζήτηση ονομάτων επαφών"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Αναζήτηση ονομάτων επαφών"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Ο ορθογρ. έλεγχος χρησιμοπ. καταχωρίσεις από τη λίστα επαφών σας"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Ο ορθογρ. έλεγχος χρησιμοπ. καταχωρίσεις από τη λίστα επαφών σας"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Δόνηση κατά το πάτημα πλήκτρων"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Δόνηση κατά το πάτημα πλήκτρων"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Input options"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Input options"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Research Log Commands"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Input options"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Input options"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Research Log Commands"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opciones de entrada"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opciones de entrada"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Comandos registro invest."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nombres contactos"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nombres contactos"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortográfico usa entradas de tu lista de contactos."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortográfico usa entradas de tu lista de contactos."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar teclas"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar teclas"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opciones entrada texto"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opciones entrada texto"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Comandos registro investigación"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Nombres de contactos"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Nombres de contactos"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Añadir nombres de tu lista de contactos al corrector"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Añadir nombres de tu lista de contactos al corrector"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar tecla"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar tecla"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Sisestusvalikud"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Sisestusvalikud"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Uuringulogi käsud"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakti nimede kontroll."</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakti nimede kontroll."</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Õigekirjakontroll kasutab teie kontaktisikute loendi sissekandeid"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Õigekirjakontroll kasutab teie kontaktisikute loendi sissekandeid"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreeri klahvivajutusel"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreeri klahvivajutusel"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"گزینههای ورودی"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"گزینههای ورودی"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"فرمانهای گزارشگیری پژوهش"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"جستجوی نام مخاطبین"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"جستجوی نام مخاطبین"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"غلطگیر املا از ورودیهای لیست مخاطبین شما استفاده میکند"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"غلطگیر املا از ورودیهای لیست مخاطبین شما استفاده میکند"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"لرزش با فشار کلید"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"لرزش با فشار کلید"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Syöttövalinnat"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Syöttövalinnat"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Tutkimuslokin komennot"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Hae yht.tietojen nimiä"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Hae yht.tietojen nimiä"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Oikeinkirjoituksen tarkistus käyttää yhteystietojasi."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Oikeinkirjoituksen tarkistus käyttää yhteystietojasi."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Commandes journaux rech."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Correcteur orthographique utilise entrées de liste de contacts."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Correcteur orthographique utilise entrées de liste de contacts."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Commandes journaux rech."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Correcteur orthographique utilise entrées de liste de contacts."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Correcteur orthographique utilise entrées de liste de contacts."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्प"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्प"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"लॉग आदेशों का शोध करें"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"संपर्क नामों को खोजें"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"संपर्क नामों को खोजें"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"वर्तनी परीक्षक आपकी संपर्क सूची की प्रविष्टियों का उपयोग करता है"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"वर्तनी परीक्षक आपकी संपर्क सूची की प्रविष्टियों का उपयोग करता है"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"कुंजी दबाने पर कंपन करता है"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"कुंजी दबाने पर कंपन करता है"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opcije ulaza"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opcije ulaza"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Istraživanje naredbi dnevnika"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Potražite imena kontakata"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Potražite imena kontakata"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Provjera pravopisa upotrebljava unose iz vašeg popisa kontakata"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Provjera pravopisa upotrebljava unose iz vašeg popisa kontakata"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibracija pri pritisku na tipku"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibracija pri pritisku na tipku"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Beviteli beállítások"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Beviteli beállítások"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Naplózási parancsok"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Névjegyek keresése"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Névjegyek keresése"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"A helyesírás-ellenőrző használja a névjegyek bejegyzéseit"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"A helyesírás-ellenőrző használja a névjegyek bejegyzéseit"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Rezgés gombnyomásra"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Rezgés gombnyomásra"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Ներածման ընտրանքներ"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Ներածման ընտրանքներ"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Հետազոտական գրառումների հրամաններ"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Փնտրել կոնտակտային անուններ"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Փնտրել կոնտակտային անուններ"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Տառասխալների ուղղիչն օգտագործում է ձեր կոնտակտների ցանկի տվյալները"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Տառասխալների ուղղիչն օգտագործում է ձեր կոնտակտների ցանկի տվյալները"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Թրթռալ սեղմման ժամանակ"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Թրթռալ սեղմման ժամանակ"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opsi masukan"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opsi masukan"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Riset Perintah Log"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kontak"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kontak"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Pemeriksa ejaan menggunakan entri dari daftar kontak Anda"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Pemeriksa ejaan menggunakan entri dari daftar kontak Anda"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar jika tombol ditekan"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar jika tombol ditekan"</string>
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<!-- no translation found for english_ime_input_options (3909945612939668554) -->
|
<!-- no translation found for english_ime_input_options (3909945612939668554) -->
|
||||||
<skip />
|
<skip />
|
||||||
<!-- no translation found for english_ime_research_log (8492602295696577851) -->
|
|
||||||
<skip />
|
<skip />
|
||||||
<!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
|
<!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
|
||||||
<skip />
|
<skip />
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opzioni inserimento"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opzioni inserimento"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Ricerca comandi di log"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca in nomi contatti"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca in nomi contatti"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"La funzione di controllo ortografico usa voci dell\'elenco contatti"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"La funzione di controllo ortografico usa voci dell\'elenco contatti"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrazione tasti"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrazione tasti"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"אפשרויות קלט"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"אפשרויות קלט"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"פקודות יומן מחקר"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"חפש שמות של אנשי קשר"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"חפש שמות של אנשי קשר"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"בודק האיות משתמש בערכים מרשימת אנשי הקשר שלך"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"בודק האיות משתמש בערכים מרשימת אנשי הקשר שלך"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"רטט בלחיצה על מקשים"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"רטט בלחיצה על מקשים"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"入力オプション"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"入力オプション"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"ログコマンドの検索"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"連絡先名の検索"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"連絡先名の検索"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"スペルチェッカーでは連絡先リストのエントリを使用します"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"スペルチェッカーでは連絡先リストのエントリを使用します"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"キー操作バイブ"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"キー操作バイブ"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"შეყვანის მეთოდები"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"შეყვანის მეთოდები"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"კვლევის აღრიცხვის ბრძანებები"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"კონტაქტებში ძებნა"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"კონტაქტებში ძებნა"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"კონტაქტების სიის გამოყენება მართლწერის შემოწმებისას"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"კონტაქტების სიის გამოყენება მართლწერის შემოწმებისას"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"ვიბრაცია კლავიშზე დაჭერისას"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"ვიბრაცია კლავიშზე დაჭერისას"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Енгізу опциялары"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Енгізу опциялары"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Журнал пәрмендерін зерттеу"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Контакт аттарын іздеу"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Контакт аттарын іздеу"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Емлені тексеру құралы контактілер тізімінің жазбаларын пайдаланады"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Емлені тексеру құралы контактілер тізімінің жазбаларын пайдаланады"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Пернені басқан кездегі діріл"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Пернені басқан кездегі діріл"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"ជម្រើសបញ្ចូល"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"ជម្រើសបញ្ចូល"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"ពាក្យបញ្ជាកំណត់ហេតុការស្រាវជ្រាវ"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"រកមើលឈ្មោះទំនាក់ទំនង"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"រកមើលឈ្មោះទំនាក់ទំនង"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"កម្មវិធីពិនិត្យអក្ខរាវិរុទ្ធប្រើធាតុពីក្នុងបញ្ជីទំនាក់ទំនងរបស់អ្នក"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"កម្មវិធីពិនិត្យអក្ខរាវិរុទ្ធប្រើធាតុពីក្នុងបញ្ជីទំនាក់ទំនងរបស់អ្នក"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"ញ័រនៅពេលចុចគ្រាប់ចុច"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"ញ័រនៅពេលចុចគ្រាប់ចុច"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"입력 옵션"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"입력 옵션"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"로그 명령 탐색"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"연락처 이름 조회"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"연락처 이름 조회"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"맞춤법 검사기가 주소록의 항목을 사용합니다."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"맞춤법 검사기가 주소록의 항목을 사용합니다."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"키를 누를 때 진동 발생"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"키를 누를 때 진동 발생"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"ຕົວເລືອກການປ້ອນຂໍ້ມູນ"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"ຕົວເລືອກການປ້ອນຂໍ້ມູນ"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Research Log Commands"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"ເບິ່ງທີ່ຊື່ຂອງລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"ເບິ່ງທີ່ຊື່ຂອງລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"ໂຕຊ່ວຍສະກົດໃຊ້ຂໍ້ມູນຈາກລາຍການຂອງລາຍຊື່ຜູ່ຕິດຕໍ່ຂອງທ່ານ"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"ໂຕຊ່ວຍສະກົດໃຊ້ຂໍ້ມູນຈາກລາຍການຂອງລາຍຊື່ຜູ່ຕິດຕໍ່ຂອງທ່ານ"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"ສັ່ນເຕືອນເມື່ອພິມ"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"ສັ່ນເຕືອນເມື່ອພິມ"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Įvesties parinktys"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Įvesties parinktys"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Tyrinėti žurnalo komandas"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktų vardų paieška"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktų vardų paieška"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Rašybos tikrinimo progr. naudoja įrašus, esančius kontaktų sąraše"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Rašybos tikrinimo progr. naudoja įrašus, esančius kontaktų sąraše"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibruoti, kai paspaudžiami klavišai"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibruoti, kai paspaudžiami klavišai"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Ievades opcijas"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Ievades opcijas"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Izpētes žurnāla komandas"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Meklēt kontaktp. vārdus"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Meklēt kontaktp. vārdus"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Pareizrakst. pārbaudītājs lieto ierakstus no kontaktp. saraksta."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Pareizrakst. pārbaudītājs lieto ierakstus no kontaktp. saraksta."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrēt, nospiežot taustiņu"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrēt, nospiežot taustiņu"</string>
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<!-- no translation found for english_ime_input_options (3909945612939668554) -->
|
<!-- no translation found for english_ime_input_options (3909945612939668554) -->
|
||||||
<skip />
|
<skip />
|
||||||
<!-- no translation found for english_ime_research_log (8492602295696577851) -->
|
|
||||||
<skip />
|
<skip />
|
||||||
<!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
|
<!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
|
||||||
<skip />
|
<skip />
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Оруулах сонголтууд"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Оруулах сонголтууд"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Судалгааны протоколын командууд"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Харилцагчийн нэр хайх"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Харилцагчийн нэр хайх"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Алдаа шалгагч нь таны харилцагчдын жагсаалтаас ашиглана"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Алдаа шалгагч нь таны харилцагчдын жагсаалтаас ашиглана"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Товч дарахад чичрэх"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Товч дарахад чичрэх"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Pilihan input"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Pilihan input"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Arahan Log Penyelidikan"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kenalan"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kenalan"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Penyemak ejaan menggunakan entri dari senarai kenalan anda"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Penyemak ejaan menggunakan entri dari senarai kenalan anda"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar pada tekanan kekunci"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar pada tekanan kekunci"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Inndataalternativer"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Inndataalternativer"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Kommandoer for undersøkelseslogging"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Slå opp kontaktnavn"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Slå opp kontaktnavn"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruker oppføringer fra kontaktlisten din"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruker oppføringer fra kontaktlisten din"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer ved tastetrykk"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer ved tastetrykk"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्पहरू"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्पहरू"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"लग निर्देशनहरू शोध गर्नुहोस्"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"सम्पर्क नामहरू हेर्नुहोस्"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"सम्पर्क नामहरू हेर्नुहोस्"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"तपाईँको सम्पर्क सूचीबाट हिज्जे परीक्षकले प्रविष्टिहरूको प्रयोग गर्छ"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"तपाईँको सम्पर्क सूचीबाट हिज्जे परीक्षकले प्रविष्टिहरूको प्रयोग गर्छ"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"कुञ्जी थिच्दा भाइब्रेट"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"कुञ्जी थिच्दा भाइब्रेट"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropties"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropties"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Opdrachten in onderzoekslogbestand"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Contactnamen opzoeken"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Contactnamen opzoeken"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"De spellingcontrole gebruikt items uit uw contactenlijst"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"De spellingcontrole gebruikt items uit uw contactenlijst"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Trillen bij toetsaanslag"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Trillen bij toetsaanslag"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opcje wprowadzania"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opcje wprowadzania"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Polecenia dziennika badań"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Przeszukaj kontakty"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Przeszukaj kontakty"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Sprawdzanie pisowni bierze pod uwagę wpisy z listy kontaktów."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Sprawdzanie pisowni bierze pod uwagę wpisy z listy kontaktów."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Wibracja przy naciśnięciu"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Wibracja przy naciśnięciu"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opções de introdução"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opções de introdução"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Comandos de Reg. Invest."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Procurar nomes de contac."</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Procurar nomes de contac."</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"O corretor ortográfico utiliza entradas da sua lista de contactos"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"O corretor ortográfico utiliza entradas da sua lista de contactos"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao primir as teclas"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao primir as teclas"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opções de entrada"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opções de entrada"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Pesq. comandos de reg."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nomes de contatos"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nomes de contatos"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"O corretor ortográfico usa entradas de sua lista de contatos"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"O corretor ortográfico usa entradas de sua lista de contatos"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao tocar a tecla"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao tocar a tecla"</string>
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<!-- no translation found for english_ime_input_options (3909945612939668554) -->
|
<!-- no translation found for english_ime_input_options (3909945612939668554) -->
|
||||||
<skip />
|
<skip />
|
||||||
<!-- no translation found for english_ime_research_log (8492602295696577851) -->
|
|
||||||
<skip />
|
<skip />
|
||||||
<!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
|
<!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
|
||||||
<skip />
|
<skip />
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Opţiuni de introducere text"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Opţiuni de introducere text"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Comenzi jurnal cercetare"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Verificare nume în agendă"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Verificare nume în agendă"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Verificatorul ortografic utilizează intrări din lista de contacte"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Verificatorul ortografic utilizează intrări din lista de contacte"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrare la apăsarea tastei"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrare la apăsarea tastei"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Настройки"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Настройки"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Все команды"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Поиск контактов"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Поиск контактов"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Обращаться к списку контактов при проверке правописания"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Обращаться к списку контактов при проверке правописания"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Виброотклик клавиш"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Виброотклик клавиш"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávania textu a údajov"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávania textu a údajov"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Príkazy denníka výskumu"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhľadať kontakty"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhľadať kontakty"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kontrola pravopisu používa záznamy z vášho zoznamu kontaktov"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kontrola pravopisu používa záznamy z vášho zoznamu kontaktov"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Pri stlačení klávesu vibrovať"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Pri stlačení klávesu vibrovať"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti vnosa"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti vnosa"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Ukazi za dnevnik raziskav"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Iskanje imen stikov"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Iskanje imen stikov"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Črkovalnik uporablja vnose s seznama stikov"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Črkovalnik uporablja vnose s seznama stikov"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibriranje ob pritisku tipke"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibriranje ob pritisku tipke"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Опције уноса"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Опције уноса"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Команде евиденције истраживања"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Потражи имена контаката"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Потражи имена контаката"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Контролор правописа користи уносе са листе контаката"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Контролор правописа користи уносе са листе контаката"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирај на притисак тастера"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирај на притисак тастера"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Inmatningsalternativ"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Inmatningsalternativ"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Loggkommandon"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Sök namn på kontakter"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Sök namn på kontakter"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"I stavningskontrollen används poster från kontaktlistan"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"I stavningskontrollen används poster från kontaktlistan"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrera vid tangenttryck"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrera vid tangenttryck"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Chaguo za uingizaji"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Chaguo za uingizaji"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Amri za Kumbukumbu za Utafiti"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Angalia majina ya unaowasiliana nao"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Angalia majina ya unaowasiliana nao"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kikagua tahajia hutumia majina yaliyoingizwa katika orodha yako ya anwani"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kikagua tahajia hutumia majina yaliyoingizwa katika orodha yako ya anwani"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Tetema unabofya kitufe"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Tetema unabofya kitufe"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"ตัวเลือกการป้อนข้อมูล"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"ตัวเลือกการป้อนข้อมูล"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"คำสั่งบันทึกการวิจัย"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"ค้นหารายชื่อติดต่อ"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"ค้นหารายชื่อติดต่อ"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"เครื่องมือตรวจการสะกดใช้รายการจากรายชื่อติดต่อของคุณ"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"เครื่องมือตรวจการสะกดใช้รายการจากรายชื่อติดต่อของคุณ"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"สั่นเมื่อกดปุ่ม"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"สั่นเมื่อกดปุ่ม"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Mga pagpipilian sa input"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Mga pagpipilian sa input"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Cmmnd sa Log ng Pnnliksik"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Maghanap pangalan contact"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Maghanap pangalan contact"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Gumagamit ang Spell Checker ng entries mula sa iyong contact list."</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Gumagamit ang Spell Checker ng entries mula sa iyong contact list."</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Mag-vibrate sa keypress"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Mag-vibrate sa keypress"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Giriş seçenekleri"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Giriş seçenekleri"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Araştırma Günlüğü Komutları"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kişi adlarını denetle"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kişi adlarını denetle"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Yazım denetleyici, kişi listenizdeki girişleri kullanır"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Yazım denetleyici, kişi listenizdeki girişleri kullanır"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Tuşa basıldığında titret"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Tuşa basıldığında titret"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Парам. введення"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Парам. введення"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Команди журналу дослідж."</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Шукати імена контактів"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Шукати імена контактів"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Програма перевірки правопису використ. записи зі списку контактів"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Програма перевірки правопису використ. записи зі списку контактів"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібр. при натисканні клавіш"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібр. при натисканні клавіш"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Tùy chọn nhập"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Tùy chọn nhập"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Lệnh ghi nhật ký cho nghiên cứu"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Tra cứu tên liên hệ"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Tra cứu tên liên hệ"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Trình kiểm tra chính tả sử dụng các mục nhập từ danh sách liên hệ của bạn"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Trình kiểm tra chính tả sử dụng các mục nhập từ danh sách liên hệ của bạn"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Rung khi nhấn phím"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Rung khi nhấn phím"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"输入选项"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"输入选项"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"研究记录命令"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查找联系人姓名"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查找联系人姓名"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼写检查工具会使用您的联系人列表中的条目"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼写检查工具会使用您的联系人列表中的条目"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"按键振动"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"按键振动"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"輸入選項"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"輸入選項"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"研究記錄指令"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查找聯絡人姓名"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查找聯絡人姓名"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼字檢查程式使用您的聯絡人名單中的各項記錄"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼字檢查程式使用您的聯絡人名單中的各項記錄"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"輸入選項"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"輸入選項"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"研究紀錄指令"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查詢聯絡人姓名"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查詢聯絡人姓名"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼字檢查程式使用您的聯絡人清單項目"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼字檢查程式使用您的聯絡人清單項目"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="english_ime_input_options" msgid="3909945612939668554">"Okukhethwa kukho kokungenayo"</string>
|
<string name="english_ime_input_options" msgid="3909945612939668554">"Okukhethwa kukho kokungenayo"</string>
|
||||||
<string name="english_ime_research_log" msgid="8492602295696577851">"Imiyalo yefayela lokungena lokucwaninga"</string>
|
|
||||||
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Bheka amagama woxhumana nabo"</string>
|
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Bheka amagama woxhumana nabo"</string>
|
||||||
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Isihloli sokupela sisebenzisa okungenayo kusuka kuhlu lalabo oxhumana nabo"</string>
|
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Isihloli sokupela sisebenzisa okungenayo kusuka kuhlu lalabo oxhumana nabo"</string>
|
||||||
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Dlidlizelisa ngokucindezela inkinobho"</string>
|
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Dlidlizelisa ngokucindezela inkinobho"</string>
|
||||||
|
|
|
@ -137,6 +137,4 @@
|
||||||
<item>tr:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
|
<item>tr:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
|
||||||
<item>qwerty</item>
|
<item>qwerty</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="settings_warning_researcher_mode">Attention! You are using the special keyboard for research purposes.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
**
|
|
||||||
** Copyright 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.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<!-- 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"></string>
|
|
||||||
<!-- Account type allowed for inclusion in user-invoked feedback logs [CHAR LIMIT=38] -->
|
|
||||||
<string name="research_account_type" translatable="false"></string>
|
|
||||||
<!-- Account domain allowed for inclusion in user-invoked feedback logs [CHAR LIMIT=38] -->
|
|
||||||
<string name="research_allowed_account_domain" translatable="false"></string>
|
|
||||||
|
|
||||||
<!-- Menu option that lets user send feedback for research purposes about the IME [CHAR LIMIT=38] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_menu_option" translatable="false">Send feedback</string>
|
|
||||||
<!-- Title of dialog box that lets user send feedback for research purposes about the IME [CHAR LIMIT=38] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_dialog_title" translatable="false">Send feedback</string>
|
|
||||||
<!-- Hint to user about the text entry field where they should enter research feedback [CHAR LIMIT=40] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_hint" translatable="false">Enter your feedback here.</string>
|
|
||||||
<!-- Message informing the user that the feedback string must not be empty [CHAR LIMIT=100] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_empty_feedback_error_message" translatable="false">The feedback field must not be empty.</string>
|
|
||||||
</resources>
|
|
|
@ -21,9 +21,6 @@
|
||||||
<!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] -->
|
<!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] -->
|
||||||
<string name="english_ime_input_options">Input options</string>
|
<string name="english_ime_input_options">Input options</string>
|
||||||
|
|
||||||
<!-- Title for Latin keyboard research log dialog, which contains special commands for users that contribute data for research. [CHAR LIMIT=33] -->
|
|
||||||
<string name="english_ime_research_log">Research Log Commands</string>
|
|
||||||
|
|
||||||
<!-- Title for the spell checker option to turn on/off contact names lookup [CHAR LIMIT=25] -->
|
<!-- Title for the spell checker option to turn on/off contact names lookup [CHAR LIMIT=25] -->
|
||||||
<string name="use_contacts_for_spellchecking_option_title">Look up contact names</string>
|
<string name="use_contacts_for_spellchecking_option_title">Look up contact names</string>
|
||||||
|
|
||||||
|
@ -166,68 +163,8 @@
|
||||||
<!-- Title for input language selection screen -->
|
<!-- Title for input language selection screen -->
|
||||||
<string name="language_selection_title">Input languages</string>
|
<string name="language_selection_title">Input languages</string>
|
||||||
|
|
||||||
<!-- Title for dialog option to let users cancel logging and delete log for this session [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_do_not_log_this_session" translatable="false">Suspend logging</string>
|
|
||||||
<!-- Title for dialog option to let users reenable logging [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_enable_session_logging" translatable="false">Enable logging</string>
|
|
||||||
<!-- Toast notification that the system is processing the request to delete the log for this session [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_notify_session_log_deleting" translatable="false">Deleting session log</string>
|
|
||||||
<!-- Toast notification that the system has successfully deleted the log for this session [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_notify_logging_suspended" translatable="false">Logging temporarily suspended. To disable permanently, go to Android Keyboard Settings</string>
|
|
||||||
<!-- Toast notification that the system has failed to delete the log for this session [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_notify_session_log_not_deleted" translatable="false">Session log NOT deleted</string>
|
|
||||||
<!-- Toast notification that the system is enabling logging [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_notify_session_logging_enabled" translatable="false">Session logging enabled</string>
|
|
||||||
|
|
||||||
<!-- Text for checkbox option to include user data in feedback for research purposes [CHAR LIMIT=50] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_include_history_label" translatable="false">Include session history</string>
|
|
||||||
<!-- Text for checkbox option to include user account name in feedback for research purposes [CHAR LIMIT=50] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_include_account_name_label" translatable="false">Include account name</string>
|
|
||||||
<!-- Text for checkbox option to include a recording in feedback for research purposes [CHAR LIMIT=50] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_include_recording_label" translatable="false">Include recorded demonstration</string>
|
|
||||||
<!-- Dialog button choice to send research feedback [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_send" translatable="false">Send</string>
|
|
||||||
<!-- Dialog button choice to cancel sending research feedback [CHAR LIMIT=35] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_cancel" translatable="false">Cancel</string>
|
|
||||||
<!-- Temporary notification to provide user with instructions about stopping a recording
|
|
||||||
- operation[CHAR LIMIT=100] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_demonstration_instructions" translatable="false">Please demonstrate the issue you are writing about.\n\nWhen finished, select the \"Bug?\" button again."</string>
|
|
||||||
<!-- Title of a preference to send feedback. [CHAR LIMIT=30]-->
|
<!-- Title of a preference to send feedback. [CHAR LIMIT=30]-->
|
||||||
<string name="send_feedback">Send feedback</string>
|
<string name="send_feedback">Send feedback</string>
|
||||||
<!-- Temporary notification of recording failure [CHAR LIMIT=100] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_feedback_recording_failure" translatable="false">Recording cancelled due to timeout</string>
|
|
||||||
<!-- Toast notification to ask user to quit the research feedback dialog to perform this operation [CHAR LIMIT=100] -->
|
|
||||||
<!-- 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">Warning</string>
|
|
||||||
|
|
||||||
<!-- Toast message informing users that logging has been disabled -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_logging_disabled" translatable="false">Logging Disabled</string>
|
|
||||||
|
|
||||||
<!-- Name for the research uploading service to be displayed to users. [CHAR LIMIT=50] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_log_uploader_name" translatable="false">Research Uploader Service</string>
|
|
||||||
|
|
||||||
<!-- Name for the research replaying service to be displayed to users. [CHAR LIMIT=50] -->
|
|
||||||
<!-- TODO: remove translatable=false attribute once text is stable -->
|
|
||||||
<string name="research_log_replayer_name" translatable="false">Research Replayer Service</string>
|
|
||||||
|
|
||||||
<!-- Preference for input language selection -->
|
<!-- Preference for input language selection -->
|
||||||
<string name="select_language">Input languages</string>
|
<string name="select_language">Input languages</string>
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
**
|
|
||||||
** Copyright 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.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<string name="research_logger_upload_url" translatable="false"></string>
|
|
||||||
</resources>
|
|
|
@ -37,9 +37,7 @@ import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
|
||||||
import com.android.inputmethod.latin.Constants;
|
import com.android.inputmethod.latin.Constants;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.utils.TypefaceUtils;
|
import com.android.inputmethod.latin.utils.TypefaceUtils;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
@ -317,13 +315,6 @@ public class KeyboardView extends View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Research Logging (Development Only Diagnostics) indicator.
|
|
||||||
// TODO: Reimplement using a keyboard background image specific to the ResearchLogger,
|
|
||||||
// and remove this call.
|
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.getInstance().paintIndicator(this, paint, canvas, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
mInvalidatedKeys.clear();
|
mInvalidatedKeys.clear();
|
||||||
mInvalidateAllKeys = false;
|
mInvalidateAllKeys = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,13 +55,11 @@ import com.android.inputmethod.latin.Constants;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
import com.android.inputmethod.latin.SuggestedWords;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.settings.DebugSettings;
|
import com.android.inputmethod.latin.settings.DebugSettings;
|
||||||
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
||||||
import com.android.inputmethod.latin.utils.SpacebarLanguageUtils;
|
import com.android.inputmethod.latin.utils.SpacebarLanguageUtils;
|
||||||
import com.android.inputmethod.latin.utils.TypefaceUtils;
|
import com.android.inputmethod.latin.utils.TypefaceUtils;
|
||||||
import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils;
|
import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
@ -387,10 +385,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
||||||
mSpaceKey = keyboard.getKey(Constants.CODE_SPACE);
|
mSpaceKey = keyboard.getKey(Constants.CODE_SPACE);
|
||||||
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
|
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
|
||||||
mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio;
|
mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio;
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
final int orientation = getContext().getResources().getConfiguration().orientation;
|
|
||||||
ResearchLogger.mainKeyboardView_setKeyboard(keyboard, orientation);
|
|
||||||
}
|
|
||||||
|
|
||||||
mAccessibilityDelegate.setKeyboard(keyboard);
|
mAccessibilityDelegate.setKeyboard(keyboard);
|
||||||
}
|
}
|
||||||
|
@ -552,24 +546,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
||||||
protected void onAttachedToWindow() {
|
protected void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
installPreviewPlacerView();
|
installPreviewPlacerView();
|
||||||
// Notify the ResearchLogger (development only diagnostics) 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.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDetachedFromWindow() {
|
protected void onDetachedFromWindow() {
|
||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
mDrawingPreviewPlacerView.removeAllViews();
|
mDrawingPreviewPlacerView.removeAllViews();
|
||||||
// Notify the ResearchLogger (development only diagnostics) that the keyboard view has
|
|
||||||
// been detached. This is needed to invalidate the reference of {@link MainKeyboardView}
|
|
||||||
// to null.
|
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) {
|
private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) {
|
||||||
|
@ -605,9 +587,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.mainKeyboardView_onLongPress();
|
|
||||||
}
|
|
||||||
final KeyboardActionListener listener = mKeyboardActionListener;
|
final KeyboardActionListener listener = mKeyboardActionListener;
|
||||||
if (key.hasNoPanelAutoMoreKey()) {
|
if (key.hasNoPanelAutoMoreKey()) {
|
||||||
final int moreKeyCode = key.getMoreKeys()[0].mCode;
|
final int moreKeyCode = key.getMoreKeys()[0].mCode;
|
||||||
|
@ -723,10 +702,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
||||||
if (LatinImeLogger.sUsabilityStudy) {
|
if (LatinImeLogger.sUsabilityStudy) {
|
||||||
UsabilityStudyLogUtils.writeMotionEvent(me);
|
UsabilityStudyLogUtils.writeMotionEvent(me);
|
||||||
}
|
}
|
||||||
// Currently the same "move" event is being logged twice.
|
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.mainKeyboardView_processMotionEvent(me);
|
|
||||||
}
|
|
||||||
|
|
||||||
final int index = me.getActionIndex();
|
final int index = me.getActionIndex();
|
||||||
final int id = me.getPointerId(index);
|
final int id = me.getPointerId(index);
|
||||||
|
|
|
@ -35,11 +35,9 @@ import com.android.inputmethod.latin.Constants;
|
||||||
import com.android.inputmethod.latin.InputPointers;
|
import com.android.inputmethod.latin.InputPointers;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.settings.Settings;
|
import com.android.inputmethod.latin.settings.Settings;
|
||||||
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
||||||
import com.android.inputmethod.latin.utils.ResourceUtils;
|
import com.android.inputmethod.latin.utils.ResourceUtils;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@ -335,10 +333,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||||
output, ignoreModifierKey ? " ignoreModifier" : "",
|
output, ignoreModifierKey ? " ignoreModifier" : "",
|
||||||
altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled"));
|
altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled"));
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey,
|
|
||||||
altersCode, code);
|
|
||||||
}
|
|
||||||
if (ignoreModifierKey) {
|
if (ignoreModifierKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -373,10 +367,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||||
withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "",
|
withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "",
|
||||||
key.isEnabled() ? "": " disabled"));
|
key.isEnabled() ? "": " disabled"));
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding,
|
|
||||||
ignoreModifierKey);
|
|
||||||
}
|
|
||||||
if (ignoreModifierKey) {
|
if (ignoreModifierKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -396,9 +386,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||||
if (DEBUG_LISTENER) {
|
if (DEBUG_LISTENER) {
|
||||||
Log.d(TAG, String.format("[%d] onCancelInput", mPointerId));
|
Log.d(TAG, String.format("[%d] onCancelInput", mPointerId));
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.pointerTracker_callListenerOnCancelInput();
|
|
||||||
}
|
|
||||||
sListener.onCancelInput();
|
sListener.onCancelInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,9 +689,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||||
Log.w(TAG, String.format("[%d] onDownEvent:"
|
Log.w(TAG, String.format("[%d] onDownEvent:"
|
||||||
+ " ignore potential noise: time=%d distance=%d",
|
+ " ignore potential noise: time=%d distance=%d",
|
||||||
mPointerId, deltaT, distance));
|
mPointerId, deltaT, distance));
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance);
|
|
||||||
}
|
|
||||||
cancelTrackingForAction();
|
cancelTrackingForAction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -876,10 +860,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
|
||||||
lastX, lastY, Constants.printableCode(oldKey.getCode()),
|
lastX, lastY, Constants.printableCode(oldKey.getCode()),
|
||||||
x, y, Constants.printableCode(key.getCode())));
|
x, y, Constants.printableCode(key.getCode())));
|
||||||
}
|
}
|
||||||
// TODO: This should be moved to outside of this nested if-clause?
|
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
|
|
||||||
}
|
|
||||||
onUpEventInternal(x, y, eventTime);
|
onUpEventInternal(x, y, eventTime);
|
||||||
onDownEventInternal(x, y, eventTime);
|
onDownEventInternal(x, y, eventTime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
@ -38,7 +37,6 @@ import android.net.ConnectivityManager;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -90,7 +88,6 @@ import com.android.inputmethod.latin.utils.JniUtils;
|
||||||
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
|
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
|
||||||
import com.android.inputmethod.latin.utils.StatsUtils;
|
import com.android.inputmethod.latin.utils.StatsUtils;
|
||||||
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
@ -494,11 +491,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
loadSettings();
|
loadSettings();
|
||||||
resetSuggest();
|
resetSuggest();
|
||||||
|
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.getInstance().init(this, mKeyboardSwitcher);
|
|
||||||
ResearchLogger.getInstance().initDictionary(mDictionaryFacilitator);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register to receive ringer mode change and network state change.
|
// Register to receive ringer mode change and network state change.
|
||||||
// Also receive installation and removal of a dictionary pack.
|
// Also receive installation and removal of a dictionary pack.
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
|
@ -631,9 +623,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mDictionaryFacilitator.closeDictionaries();
|
mDictionaryFacilitator.closeDictionaries();
|
||||||
mSettings.onDestroy();
|
mSettings.onDestroy();
|
||||||
unregisterReceiver(mConnectivityAndRingerModeChangeReceiver);
|
unregisterReceiver(mConnectivityAndRingerModeChangeReceiver);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.getInstance().onDestroy();
|
|
||||||
}
|
|
||||||
unregisterReceiver(mDictionaryPackInstallReceiver);
|
unregisterReceiver(mDictionaryPackInstallReceiver);
|
||||||
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
|
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
|
||||||
PersonalizationDictionarySessionRegistrar.close(this);
|
PersonalizationDictionarySessionRegistrar.close(this);
|
||||||
|
@ -757,10 +746,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
}
|
}
|
||||||
Log.i(TAG, "Starting input. Cursor position = "
|
Log.i(TAG, "Starting input. Cursor position = "
|
||||||
+ editorInfo.initialSelStart + "," + editorInfo.initialSelEnd);
|
+ editorInfo.initialSelStart + "," + editorInfo.initialSelEnd);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs);
|
|
||||||
}
|
|
||||||
if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
|
if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
|
||||||
Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions);
|
Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions);
|
||||||
Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead");
|
Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead");
|
||||||
|
@ -905,10 +890,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mHandler.cancelUpdateSuggestionStrip();
|
mHandler.cancelUpdateSuggestionStrip();
|
||||||
// Should do the following in onFinishInputInternal but until JB MR2 it's not called :(
|
// Should do the following in onFinishInputInternal but until JB MR2 it's not called :(
|
||||||
mInputLogic.finishInput();
|
mInputLogic.finishInput();
|
||||||
// Notify ResearchLogger
|
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -922,11 +903,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
+ ", nss=" + newSelStart + ", nse=" + newSelEnd
|
+ ", nss=" + newSelStart + ", nse=" + newSelEnd
|
||||||
+ ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd);
|
+ ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd);
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onUpdateSelection(oldSelStart, oldSelEnd,
|
|
||||||
oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart,
|
|
||||||
composingSpanEnd, mInputLogic.mConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the keyboard is not visible, we don't need to do all the housekeeping work, as it
|
// If the keyboard is not visible, we don't need to do all the housekeeping work, as it
|
||||||
// will be reset when the keyboard shows up anyway.
|
// will be reset when the keyboard shows up anyway.
|
||||||
|
@ -1013,9 +989,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
}
|
}
|
||||||
if (applicationSpecifiedCompletions == null) {
|
if (applicationSpecifiedCompletions == null) {
|
||||||
setNeutralSuggestionStrip();
|
setNeutralSuggestionStrip();
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onDisplayCompletions(null);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,9 +1000,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
false /* isObsoleteSuggestions */, false /* isPrediction */);
|
false /* isObsoleteSuggestions */, false /* isPrediction */);
|
||||||
// When in fullscreen mode, show completions generated by the application forcibly
|
// When in fullscreen mode, show completions generated by the application forcibly
|
||||||
setSuggestedWords(suggestedWords, true /* isSuggestionStripVisible */);
|
setSuggestedWords(suggestedWords, true /* isSuggestionStripVisible */);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getAdjustedBackingViewHeight() {
|
private int getAdjustedBackingViewHeight() {
|
||||||
|
|
|
@ -26,14 +26,12 @@ import android.view.inputmethod.ExtractedText;
|
||||||
import android.view.inputmethod.ExtractedTextRequest;
|
import android.view.inputmethod.ExtractedTextRequest;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
||||||
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
||||||
import com.android.inputmethod.latin.utils.DebugLogUtils;
|
import com.android.inputmethod.latin.utils.DebugLogUtils;
|
||||||
import com.android.inputmethod.latin.utils.SpannableStringUtils;
|
import com.android.inputmethod.latin.utils.SpannableStringUtils;
|
||||||
import com.android.inputmethod.latin.utils.StringUtils;
|
import com.android.inputmethod.latin.utils.StringUtils;
|
||||||
import com.android.inputmethod.latin.utils.TextRange;
|
import com.android.inputmethod.latin.utils.TextRange;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -174,9 +172,6 @@ public final class RichInputConnection {
|
||||||
}
|
}
|
||||||
if (null != mIC && shouldFinishComposition) {
|
if (null != mIC && shouldFinishComposition) {
|
||||||
mIC.finishComposingText();
|
mIC.finishComposingText();
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_finishComposingText();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -223,9 +218,6 @@ public final class RichInputConnection {
|
||||||
mComposingText.setLength(0);
|
mComposingText.setLength(0);
|
||||||
if (null != mIC) {
|
if (null != mIC) {
|
||||||
mIC.finishComposingText();
|
mIC.finishComposingText();
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_finishComposingText();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,9 +355,6 @@ public final class RichInputConnection {
|
||||||
}
|
}
|
||||||
if (null != mIC) {
|
if (null != mIC) {
|
||||||
mIC.deleteSurroundingText(beforeLength, afterLength);
|
mIC.deleteSurroundingText(beforeLength, afterLength);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_deleteSurroundingText(beforeLength, afterLength);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
||||||
}
|
}
|
||||||
|
@ -374,9 +363,6 @@ public final class RichInputConnection {
|
||||||
mIC = mParent.getCurrentInputConnection();
|
mIC = mParent.getCurrentInputConnection();
|
||||||
if (null != mIC) {
|
if (null != mIC) {
|
||||||
mIC.performEditorAction(actionId);
|
mIC.performEditorAction(actionId);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_performEditorAction(actionId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,9 +415,6 @@ public final class RichInputConnection {
|
||||||
}
|
}
|
||||||
if (null != mIC) {
|
if (null != mIC) {
|
||||||
mIC.sendKeyEvent(keyEvent);
|
mIC.sendKeyEvent(keyEvent);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_sendKeyEvent(keyEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,9 +452,6 @@ public final class RichInputConnection {
|
||||||
// newCursorPosition != 1.
|
// newCursorPosition != 1.
|
||||||
if (null != mIC) {
|
if (null != mIC) {
|
||||||
mIC.setComposingText(text, newCursorPosition);
|
mIC.setComposingText(text, newCursorPosition);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_setComposingText(text, newCursorPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
||||||
}
|
}
|
||||||
|
@ -500,9 +480,6 @@ public final class RichInputConnection {
|
||||||
if (!isIcValid) {
|
if (!isIcValid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_setSelection(start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return reloadTextCache();
|
return reloadTextCache();
|
||||||
}
|
}
|
||||||
|
@ -530,9 +507,6 @@ public final class RichInputConnection {
|
||||||
mComposingText.setLength(0);
|
mComposingText.setLength(0);
|
||||||
if (null != mIC) {
|
if (null != mIC) {
|
||||||
mIC.commitCompletion(completionInfo);
|
mIC.commitCompletion(completionInfo);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_commitCompletion(completionInfo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
||||||
}
|
}
|
||||||
|
@ -765,9 +739,6 @@ public final class RichInputConnection {
|
||||||
deleteSurroundingText(2, 0);
|
deleteSurroundingText(2, 0);
|
||||||
final String singleSpace = " ";
|
final String singleSpace = " ";
|
||||||
commitText(singleSpace, 1);
|
commitText(singleSpace, 1);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_revertDoubleSpacePeriod();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,9 +761,6 @@ public final class RichInputConnection {
|
||||||
deleteSurroundingText(2, 0);
|
deleteSurroundingText(2, 0);
|
||||||
final String text = " " + textBeforeCursor.subSequence(0, 1);
|
final String text = " " + textBeforeCursor.subSequence(0, 1);
|
||||||
commitText(text, 1);
|
commitText(text, 1);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.richInputConnection_revertSwapPunctuation();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,6 @@ public final class ProductionFlag {
|
||||||
// This class is not publicly instantiable.
|
// This class is not publicly instantiable.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean USES_DEVELOPMENT_ONLY_DIAGNOSTICS = false;
|
|
||||||
|
|
||||||
// When false, USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG suggests that all guarded
|
|
||||||
// class-private DEBUG flags should be false, and any privacy controls should be enforced.
|
|
||||||
// USES_DEVELOPMENT_ONLY_DIAGNOSTICS must be false for any production build.
|
|
||||||
public static final boolean USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG = false;
|
|
||||||
|
|
||||||
public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = false;
|
public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = false;
|
||||||
|
|
||||||
// When true, enable {@link InputMethodService#onUpdateCursor} callback with
|
// When true, enable {@link InputMethodService#onUpdateCursor} callback with
|
||||||
|
|
|
@ -44,7 +44,6 @@ import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
import com.android.inputmethod.latin.SuggestedWords;
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||||
import com.android.inputmethod.latin.WordComposer;
|
import com.android.inputmethod.latin.WordComposer;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.settings.SettingsValues;
|
import com.android.inputmethod.latin.settings.SettingsValues;
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
||||||
import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
|
import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
|
||||||
|
@ -54,7 +53,6 @@ import com.android.inputmethod.latin.utils.LatinImeLoggerUtils;
|
||||||
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
|
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
|
||||||
import com.android.inputmethod.latin.utils.StringUtils;
|
import com.android.inputmethod.latin.utils.StringUtils;
|
||||||
import com.android.inputmethod.latin.utils.TextRange;
|
import com.android.inputmethod.latin.utils.TextRange;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
@ -201,19 +199,11 @@ public final class InputLogic {
|
||||||
resetComposingState(true /* alsoResetLastComposedWord */);
|
resetComposingState(true /* alsoResetLastComposedWord */);
|
||||||
}
|
}
|
||||||
handler.postUpdateSuggestionStrip();
|
handler.postUpdateSuggestionStrip();
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS
|
|
||||||
&& ResearchLogger.RESEARCH_KEY_OUTPUT_TEXT.equals(rawText)) {
|
|
||||||
ResearchLogger.getInstance().onResearchKeySelected(mLatinIME);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String text = performSpecificTldProcessingOnTextInput(rawText);
|
final String text = performSpecificTldProcessingOnTextInput(rawText);
|
||||||
if (SpaceState.PHANTOM == mSpaceState) {
|
if (SpaceState.PHANTOM == mSpaceState) {
|
||||||
promotePhantomSpace(settingsValues);
|
promotePhantomSpace(settingsValues);
|
||||||
}
|
}
|
||||||
mConnection.commitText(text, 1);
|
mConnection.commitText(text, 1);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onTextInput(text, false /* isBatchMode */);
|
|
||||||
}
|
|
||||||
mConnection.endBatchEdit();
|
mConnection.endBatchEdit();
|
||||||
// Space state must be updated before calling updateShiftState
|
// Space state must be updated before calling updateShiftState
|
||||||
mSpaceState = SpaceState.NONE;
|
mSpaceState = SpaceState.NONE;
|
||||||
|
@ -244,10 +234,6 @@ public final class InputLogic {
|
||||||
LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords);
|
LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords);
|
||||||
// Rely on onCodeInput to do the complicated swapping/stripping logic consistently.
|
// Rely on onCodeInput to do the complicated swapping/stripping logic consistently.
|
||||||
final Event event = Event.createPunctuationSuggestionPickedEvent(suggestionInfo);
|
final Event event = Event.createPunctuationSuggestionPickedEvent(suggestionInfo);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_punctuationSuggestion(index, suggestion,
|
|
||||||
false /* isBatchMode */, suggestedWords.mIsPrediction);
|
|
||||||
}
|
|
||||||
return onCodeInput(settingsValues, event, keyboardShiftState, handler);
|
return onCodeInput(settingsValues, event, keyboardShiftState, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,11 +272,6 @@ public final class InputLogic {
|
||||||
LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords);
|
LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords);
|
||||||
commitChosenWord(settingsValues, suggestion,
|
commitChosenWord(settingsValues, suggestion,
|
||||||
LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR);
|
LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion,
|
|
||||||
mWordComposer.isBatchMode(), suggestionInfo.mScore,
|
|
||||||
suggestionInfo.mKindAndFlags, suggestionInfo.mSourceDict.mDictType);
|
|
||||||
}
|
|
||||||
mConnection.endBatchEdit();
|
mConnection.endBatchEdit();
|
||||||
// Don't allow cancellation of manual pick
|
// Don't allow cancellation of manual pick
|
||||||
mLastComposedWord.deactivate();
|
mLastComposedWord.deactivate();
|
||||||
|
@ -403,9 +384,6 @@ public final class InputLogic {
|
||||||
final InputTransaction inputTransaction = new InputTransaction(settingsValues, event,
|
final InputTransaction inputTransaction = new InputTransaction(settingsValues, event,
|
||||||
SystemClock.uptimeMillis(), mSpaceState,
|
SystemClock.uptimeMillis(), mSpaceState,
|
||||||
getActualCapsMode(settingsValues, keyboardShiftMode));
|
getActualCapsMode(settingsValues, keyboardShiftMode));
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onCodeInput(code, event.mX, event.mY);
|
|
||||||
}
|
|
||||||
if (event.mKeyCode != Constants.CODE_DELETE
|
if (event.mKeyCode != Constants.CODE_DELETE
|
||||||
|| inputTransaction.mTimestamp > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) {
|
|| inputTransaction.mTimestamp > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) {
|
||||||
mDeleteCount = 0;
|
mDeleteCount = 0;
|
||||||
|
@ -854,9 +832,6 @@ public final class InputLogic {
|
||||||
if (needsPrecedingSpace) {
|
if (needsPrecedingSpace) {
|
||||||
promotePhantomSpace(settingsValues);
|
promotePhantomSpace(settingsValues);
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!shouldAvoidSendingCode) {
|
if (!shouldAvoidSendingCode) {
|
||||||
sendKeyCodePoint(settingsValues, codePoint);
|
sendKeyCodePoint(settingsValues, codePoint);
|
||||||
|
@ -932,10 +907,6 @@ public final class InputLogic {
|
||||||
}
|
}
|
||||||
if (mWordComposer.isComposingWord()) {
|
if (mWordComposer.isComposingWord()) {
|
||||||
if (mWordComposer.isBatchMode()) {
|
if (mWordComposer.isBatchMode()) {
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
final String word = mWordComposer.getTypedWord();
|
|
||||||
ResearchLogger.latinIME_handleBackspace_batch(word, 1);
|
|
||||||
}
|
|
||||||
final String rejectedSuggestion = mWordComposer.getTypedWord();
|
final String rejectedSuggestion = mWordComposer.getTypedWord();
|
||||||
mWordComposer.reset();
|
mWordComposer.reset();
|
||||||
mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion);
|
mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion);
|
||||||
|
@ -961,9 +932,6 @@ public final class InputLogic {
|
||||||
// This is triggered on backspace after a key that inputs multiple characters,
|
// This is triggered on backspace after a key that inputs multiple characters,
|
||||||
// like the smiley key or the .com key.
|
// like the smiley key or the .com key.
|
||||||
mConnection.deleteSurroundingText(mEnteredText.length(), 0);
|
mConnection.deleteSurroundingText(mEnteredText.length(), 0);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_handleBackspace_cancelTextInput(mEnteredText);
|
|
||||||
}
|
|
||||||
mEnteredText = null;
|
mEnteredText = null;
|
||||||
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
|
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
|
||||||
// In addition we know that spaceState is false, and that we should not be
|
// In addition we know that spaceState is false, and that we should not be
|
||||||
|
@ -993,10 +961,6 @@ public final class InputLogic {
|
||||||
mConnection.setSelection(mConnection.getExpectedSelectionEnd(),
|
mConnection.setSelection(mConnection.getExpectedSelectionEnd(),
|
||||||
mConnection.getExpectedSelectionEnd());
|
mConnection.getExpectedSelectionEnd());
|
||||||
mConnection.deleteSurroundingText(numCharsDeleted, 0);
|
mConnection.deleteSurroundingText(numCharsDeleted, 0);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_handleBackspace(numCharsDeleted,
|
|
||||||
false /* shouldUncommitLogUnit */);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// There is no selection, just delete one character.
|
// There is no selection, just delete one character.
|
||||||
if (Constants.NOT_A_CURSOR_POSITION == mConnection.getExpectedSelectionEnd()) {
|
if (Constants.NOT_A_CURSOR_POSITION == mConnection.getExpectedSelectionEnd()) {
|
||||||
|
@ -1031,10 +995,6 @@ public final class InputLogic {
|
||||||
final int lengthToDelete =
|
final int lengthToDelete =
|
||||||
Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
|
Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
|
||||||
mConnection.deleteSurroundingText(lengthToDelete, 0);
|
mConnection.deleteSurroundingText(lengthToDelete, 0);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_handleBackspace(lengthToDelete,
|
|
||||||
true /* shouldUncommitLogUnit */);
|
|
||||||
}
|
|
||||||
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
|
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
|
||||||
final int codePointBeforeCursorToDeleteAgain =
|
final int codePointBeforeCursorToDeleteAgain =
|
||||||
mConnection.getCodePointBeforeCursor();
|
mConnection.getCodePointBeforeCursor();
|
||||||
|
@ -1042,10 +1002,6 @@ public final class InputLogic {
|
||||||
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
||||||
codePointBeforeCursorToDeleteAgain) ? 2 : 1;
|
codePointBeforeCursorToDeleteAgain) ? 2 : 1;
|
||||||
mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
|
mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain,
|
|
||||||
true /* shouldUncommitLogUnit */);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1083,9 +1039,6 @@ public final class InputLogic {
|
||||||
mConnection.deleteSurroundingText(2, 0);
|
mConnection.deleteSurroundingText(2, 0);
|
||||||
final String text = lastTwo.charAt(1) + " ";
|
final String text = lastTwo.charAt(1) + " ";
|
||||||
mConnection.commitText(text, 1);
|
mConnection.commitText(text, 1);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text);
|
|
||||||
}
|
|
||||||
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
|
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1169,10 +1122,6 @@ public final class InputLogic {
|
||||||
final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
|
final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
|
||||||
.mSentenceSeparatorAndSpace;
|
.mSentenceSeparatorAndSpace;
|
||||||
mConnection.commitText(textToInsert, 1);
|
mConnection.commitText(textToInsert, 1);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert,
|
|
||||||
false /* isBatchMode */);
|
|
||||||
}
|
|
||||||
mWordComposer.discardPreviousWordForSuggestion();
|
mWordComposer.discardPreviousWordForSuggestion();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1519,13 +1468,7 @@ public final class InputLogic {
|
||||||
LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString,
|
LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString,
|
||||||
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
|
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
// Don't restart suggestion yet. We'll restart if the user deletes the separator.
|
||||||
ResearchLogger.latinIME_revertCommit(committedWord.toString(),
|
|
||||||
originallyTypedWord.toString(),
|
|
||||||
mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString);
|
|
||||||
}
|
|
||||||
// Don't restart suggestion yet. We'll restart if the user deletes the
|
|
||||||
// separator.
|
|
||||||
mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
|
mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
|
||||||
// We have a separator between the word and the cursor: we should show predictions.
|
// We have a separator between the word and the cursor: we should show predictions.
|
||||||
inputTransaction.setRequiresUpdateSuggestions();
|
inputTransaction.setRequiresUpdateSuggestions();
|
||||||
|
@ -1789,9 +1732,6 @@ public final class InputLogic {
|
||||||
*/
|
*/
|
||||||
// TODO: replace these two parameters with an InputTransaction
|
// TODO: replace these two parameters with an InputTransaction
|
||||||
private void sendKeyCodePoint(final SettingsValues settingsValues, final int codePoint) {
|
private void sendKeyCodePoint(final SettingsValues settingsValues, final int codePoint) {
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_sendKeyCodePoint(codePoint);
|
|
||||||
}
|
|
||||||
// TODO: Remove this special handling of digit letters.
|
// TODO: Remove this special handling of digit letters.
|
||||||
// For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}.
|
// For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}.
|
||||||
if (codePoint >= '0' && codePoint <= '9') {
|
if (codePoint >= '0' && codePoint <= '9') {
|
||||||
|
@ -1823,9 +1763,6 @@ public final class InputLogic {
|
||||||
if (settingsValues.shouldInsertSpacesAutomatically()
|
if (settingsValues.shouldInsertSpacesAutomatically()
|
||||||
&& settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
|
&& settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
|
||||||
&& !mConnection.textBeforeCursorLooksLikeURL()) {
|
&& !mConnection.textBeforeCursorLooksLikeURL()) {
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_promotePhantomSpace();
|
|
||||||
}
|
|
||||||
sendKeyCodePoint(settingsValues, Constants.CODE_SPACE);
|
sendKeyCodePoint(settingsValues, Constants.CODE_SPACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1867,9 +1804,6 @@ public final class InputLogic {
|
||||||
mConnection.setComposingText(batchInputText, 1);
|
mConnection.setComposingText(batchInputText, 1);
|
||||||
}
|
}
|
||||||
mConnection.endBatchEdit();
|
mConnection.endBatchEdit();
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords);
|
|
||||||
}
|
|
||||||
// Space state must be updated before calling updateShiftState
|
// Space state must be updated before calling updateShiftState
|
||||||
mSpaceState = SpaceState.PHANTOM;
|
mSpaceState = SpaceState.PHANTOM;
|
||||||
keyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(settingsValues),
|
keyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(settingsValues),
|
||||||
|
@ -1896,9 +1830,6 @@ public final class InputLogic {
|
||||||
if (!mWordComposer.isComposingWord()) return;
|
if (!mWordComposer.isComposingWord()) return;
|
||||||
final String typedWord = mWordComposer.getTypedWord();
|
final String typedWord = mWordComposer.getTypedWord();
|
||||||
if (typedWord.length() > 0) {
|
if (typedWord.length() > 0) {
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode());
|
|
||||||
}
|
|
||||||
commitChosenWord(settingsValues, typedWord,
|
commitChosenWord(settingsValues, typedWord,
|
||||||
LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString);
|
LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString);
|
||||||
}
|
}
|
||||||
|
@ -1942,11 +1873,6 @@ public final class InputLogic {
|
||||||
LatinImeLoggerUtils.onAutoCorrection(
|
LatinImeLoggerUtils.onAutoCorrection(
|
||||||
typedWord, autoCorrection, separator, mWordComposer);
|
typedWord, autoCorrection, separator, mWordComposer);
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
final SuggestedWords suggestedWords = mSuggestedWords;
|
|
||||||
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection,
|
|
||||||
separator, mWordComposer.isBatchMode(), suggestedWords);
|
|
||||||
}
|
|
||||||
commitChosenWord(settingsValues, autoCorrection,
|
commitChosenWord(settingsValues, autoCorrection,
|
||||||
LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator);
|
LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator);
|
||||||
if (!typedWord.equals(autoCorrection)) {
|
if (!typedWord.equals(autoCorrection)) {
|
||||||
|
|
|
@ -76,7 +76,6 @@ public final class DebugSettings extends PreferenceFragment
|
||||||
final CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
|
final CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
|
||||||
checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE,
|
checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE,
|
||||||
LatinImeLogger.getUsabilityStudyMode(prefs)));
|
LatinImeLogger.getUsabilityStudyMode(prefs)));
|
||||||
checkbox.setSummary(R.string.settings_warning_researcher_mode);
|
|
||||||
}
|
}
|
||||||
final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING);
|
final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING);
|
||||||
if (statisticsLoggingPref instanceof CheckBoxPreference) {
|
if (statisticsLoggingPref instanceof CheckBoxPreference) {
|
||||||
|
|
|
@ -41,7 +41,6 @@ import com.android.inputmethod.keyboard.KeyboardTheme;
|
||||||
import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
|
import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
|
import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
|
||||||
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
|
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
|
||||||
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
|
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
|
||||||
|
@ -152,10 +151,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment
|
||||||
miscSettings.removePreference(aboutSettings);
|
miscSettings.removePreference(aboutSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
// The about screen contains items that may be confusing in development-only versions.
|
|
||||||
miscSettings.removePreference(aboutSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean showVoiceKeyOption = res.getBoolean(
|
final boolean showVoiceKeyOption = res.getBoolean(
|
||||||
R.bool.config_enable_show_voice_key_option);
|
R.bool.config_enable_show_voice_key_option);
|
||||||
|
|
|
@ -47,11 +47,9 @@ import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
import com.android.inputmethod.latin.SuggestedWords;
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.latin.settings.Settings;
|
import com.android.inputmethod.latin.settings.Settings;
|
||||||
import com.android.inputmethod.latin.suggestions.MoreSuggestionsView.MoreSuggestionsListener;
|
import com.android.inputmethod.latin.suggestions.MoreSuggestionsView.MoreSuggestionsListener;
|
||||||
import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
|
import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
|
||||||
import com.android.inputmethod.research.ResearchLogger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@ -226,9 +224,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
|
||||||
mSuggestedWords = suggestedWords;
|
mSuggestedWords = suggestedWords;
|
||||||
mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip(
|
mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip(
|
||||||
mSuggestedWords, mSuggestionsStrip, this);
|
mSuggestedWords, mSuggestionsStrip, this);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
|
||||||
ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords);
|
|
||||||
}
|
|
||||||
mStripVisibilityGroup.showSuggestionsStrip(isVoiceKeyEnabled());
|
mStripVisibilityGroup.showSuggestionsStrip(isVoiceKeyEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordFragmen
|
||||||
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
|
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
|
||||||
import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker;
|
import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker;
|
||||||
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
|
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
|
||||||
import com.android.inputmethod.research.FeedbackFragment;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
@ -43,7 +42,6 @@ public class FragmentUtils {
|
||||||
sLatinImeFragments.add(UserDictionaryList.class.getName());
|
sLatinImeFragments.add(UserDictionaryList.class.getName());
|
||||||
sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName());
|
sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName());
|
||||||
sLatinImeFragments.add(UserDictionarySettings.class.getName());
|
sLatinImeFragments.add(UserDictionarySettings.class.getName());
|
||||||
sLatinImeFragments.add(FeedbackFragment.class.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidFragment(String fragmentName) {
|
public static boolean isValidFragment(String fragmentName) {
|
||||||
|
|
|
@ -43,7 +43,6 @@ import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public final class UsabilityStudyLogUtils {
|
public final class UsabilityStudyLogUtils {
|
||||||
// TODO: remove code duplication with ResearchLog class
|
|
||||||
private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
|
private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
|
||||||
private static final String FILENAME = "log.txt";
|
private static final String FILENAME = "log.txt";
|
||||||
private final Handler mLoggingHandler;
|
private final Handler mLoggingHandler;
|
||||||
|
@ -190,7 +189,7 @@ public final class UsabilityStudyLogUtils {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void emailResearcherLogsAll() {
|
public void emailUsabilityStudyLogsAll() {
|
||||||
mLoggingHandler.post(new Runnable() {
|
mLoggingHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -210,7 +209,7 @@ public final class UsabilityStudyLogUtils {
|
||||||
}
|
}
|
||||||
mWriter.flush();
|
mWriter.flush();
|
||||||
final String destPath = Environment.getExternalStorageDirectory()
|
final String destPath = Environment.getExternalStorageDirectory()
|
||||||
+ "/research-" + currentDateTimeString + ".log";
|
+ "/usability-" + currentDateTimeString + ".log";
|
||||||
final File destFile = new File(destPath);
|
final File destFile = new File(destPath);
|
||||||
try {
|
try {
|
||||||
final FileInputStream srcStream = new FileInputStream(mFile);
|
final FileInputStream srcStream = new FileInputStream(mFile);
|
||||||
|
@ -241,7 +240,7 @@ public final class UsabilityStudyLogUtils {
|
||||||
intent.setType("text/plain");
|
intent.setType("text/plain");
|
||||||
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath));
|
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath));
|
||||||
intent.putExtra(Intent.EXTRA_SUBJECT,
|
intent.putExtra(Intent.EXTRA_SUBJECT,
|
||||||
"[Research Logs] " + currentDateTimeString);
|
"[Usability Study Logs] " + currentDateTimeString);
|
||||||
mIms.startActivity(intent);
|
mIms.startActivity(intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Arrange for the uploading service to be run on regular intervals.
|
|
||||||
*/
|
|
||||||
public final class BootBroadcastReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
|
||||||
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
|
|
||||||
UploaderService.cancelAndRescheduleUploadingService(context,
|
|
||||||
true /* needsRescheduling */);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
|
|
||||||
public class FeedbackActivity extends Activity {
|
|
||||||
@Override
|
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.research_feedback_activity);
|
|
||||||
final FeedbackLayout layout = (FeedbackLayout) findViewById(R.id.research_feedback_layout);
|
|
||||||
layout.setActivity(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
ResearchLogger.getInstance().onLeavingSendFeedbackDialog();
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
|
|
||||||
public class FeedbackFragment extends Fragment implements OnClickListener {
|
|
||||||
private static final String TAG = FeedbackFragment.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final String KEY_FEEDBACK_STRING = "FeedbackString";
|
|
||||||
public static final String KEY_INCLUDE_ACCOUNT_NAME = "IncludeAccountName";
|
|
||||||
public static final String KEY_HAS_USER_RECORDING = "HasRecording";
|
|
||||||
|
|
||||||
private EditText mEditText;
|
|
||||||
private CheckBox mIncludingAccountNameCheckBox;
|
|
||||||
private CheckBox mIncludingUserRecordingCheckBox;
|
|
||||||
private Button mSendButton;
|
|
||||||
private Button mCancelButton;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
final View view = inflater.inflate(R.layout.research_feedback_fragment_layout, container,
|
|
||||||
false);
|
|
||||||
mEditText = (EditText) view.findViewById(R.id.research_feedback_contents);
|
|
||||||
mEditText.requestFocus();
|
|
||||||
mIncludingAccountNameCheckBox = (CheckBox) view.findViewById(
|
|
||||||
R.id.research_feedback_include_account_name);
|
|
||||||
mIncludingUserRecordingCheckBox = (CheckBox) view.findViewById(
|
|
||||||
R.id.research_feedback_include_recording_checkbox);
|
|
||||||
mIncludingUserRecordingCheckBox.setOnClickListener(this);
|
|
||||||
|
|
||||||
mSendButton = (Button) view.findViewById(R.id.research_feedback_send_button);
|
|
||||||
mSendButton.setOnClickListener(this);
|
|
||||||
mCancelButton = (Button) view.findViewById(R.id.research_feedback_cancel_button);
|
|
||||||
mCancelButton.setOnClickListener(this);
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
|
||||||
restoreState(savedInstanceState);
|
|
||||||
} else {
|
|
||||||
final Bundle bundle = getActivity().getIntent().getExtras();
|
|
||||||
if (bundle != null) {
|
|
||||||
restoreState(bundle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(final View view) {
|
|
||||||
final ResearchLogger researchLogger = ResearchLogger.getInstance();
|
|
||||||
if (view == mIncludingUserRecordingCheckBox) {
|
|
||||||
if (mIncludingUserRecordingCheckBox.isChecked()) {
|
|
||||||
final Bundle bundle = new Bundle();
|
|
||||||
onSaveInstanceState(bundle);
|
|
||||||
|
|
||||||
// Let the user make a recording
|
|
||||||
getActivity().finish();
|
|
||||||
|
|
||||||
researchLogger.setFeedbackDialogBundle(bundle);
|
|
||||||
researchLogger.onLeavingSendFeedbackDialog();
|
|
||||||
researchLogger.startRecording();
|
|
||||||
}
|
|
||||||
} else if (view == mSendButton) {
|
|
||||||
final Editable editable = mEditText.getText();
|
|
||||||
final String feedbackContents = editable.toString();
|
|
||||||
if (TextUtils.isEmpty(feedbackContents)) {
|
|
||||||
Toast.makeText(getActivity(),
|
|
||||||
R.string.research_feedback_empty_feedback_error_message,
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
} else {
|
|
||||||
final boolean isIncludingAccountName = mIncludingAccountNameCheckBox.isChecked();
|
|
||||||
researchLogger.sendFeedback(feedbackContents, false /* isIncludingHistory */,
|
|
||||||
isIncludingAccountName, mIncludingUserRecordingCheckBox.isChecked());
|
|
||||||
getActivity().finish();
|
|
||||||
researchLogger.setFeedbackDialogBundle(null);
|
|
||||||
researchLogger.onLeavingSendFeedbackDialog();
|
|
||||||
}
|
|
||||||
} else if (view == mCancelButton) {
|
|
||||||
Log.d(TAG, "Finishing");
|
|
||||||
getActivity().finish();
|
|
||||||
researchLogger.setFeedbackDialogBundle(null);
|
|
||||||
researchLogger.onLeavingSendFeedbackDialog();
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Unknown view passed to FeedbackFragment.onClick()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(final Bundle bundle) {
|
|
||||||
final String savedFeedbackString = mEditText.getText().toString();
|
|
||||||
|
|
||||||
bundle.putString(KEY_FEEDBACK_STRING, savedFeedbackString);
|
|
||||||
bundle.putBoolean(KEY_INCLUDE_ACCOUNT_NAME, mIncludingAccountNameCheckBox.isChecked());
|
|
||||||
bundle.putBoolean(KEY_HAS_USER_RECORDING, mIncludingUserRecordingCheckBox.isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void restoreState(final Bundle bundle) {
|
|
||||||
mEditText.setText(bundle.getString(KEY_FEEDBACK_STRING));
|
|
||||||
mIncludingAccountNameCheckBox.setChecked(bundle.getBoolean(KEY_INCLUDE_ACCOUNT_NAME));
|
|
||||||
mIncludingUserRecordingCheckBox.setChecked(bundle.getBoolean(KEY_HAS_USER_RECORDING));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
public class FeedbackLayout extends LinearLayout {
|
|
||||||
private Activity mActivity;
|
|
||||||
|
|
||||||
public FeedbackLayout(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FeedbackLayout(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FeedbackLayout(Context context, AttributeSet attrs, int defstyle) {
|
|
||||||
super(context, attrs, defstyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setActivity(Activity activity) {
|
|
||||||
mActivity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean dispatchKeyEventPreIme(KeyEvent event) {
|
|
||||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
|
||||||
KeyEvent.DispatcherState state = getKeyDispatcherState();
|
|
||||||
if (state != null) {
|
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN
|
|
||||||
&& event.getRepeatCount() == 0) {
|
|
||||||
state.startTracking(event, this);
|
|
||||||
return true;
|
|
||||||
} else if (event.getAction() == KeyEvent.ACTION_UP
|
|
||||||
&& !event.isCanceled() && state.isTracking(event)) {
|
|
||||||
mActivity.onBackPressed();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.dispatchKeyEventPreIme(event);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class FeedbackLog extends ResearchLog {
|
|
||||||
public FeedbackLog(final File outputFile, final Context context) {
|
|
||||||
super(outputFile, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFeedbackLog() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,174 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A buffer that holds a fixed number of LogUnits.
|
|
||||||
*
|
|
||||||
* LogUnits are added in and shifted out in temporal order. Only a subset of the LogUnits are
|
|
||||||
* actual words; the other LogUnits do not count toward the word limit. Once the buffer reaches
|
|
||||||
* capacity, adding another LogUnit that is a word evicts the oldest LogUnits out one at a time to
|
|
||||||
* stay under the capacity limit.
|
|
||||||
*
|
|
||||||
* This variant of a LogBuffer has a limited memory footprint because of its limited size. This
|
|
||||||
* makes it useful, for example, for recording a window of the user's most recent actions in case
|
|
||||||
* they want to report an observed error that they do not know how to reproduce.
|
|
||||||
*/
|
|
||||||
public class FixedLogBuffer extends LogBuffer {
|
|
||||||
/* package for test */ int mWordCapacity;
|
|
||||||
// The number of members of mLogUnits that are actual words.
|
|
||||||
private int mNumActualWords;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LogBuffer that can hold a fixed number of LogUnits that are words (and
|
|
||||||
* unlimited number of non-word LogUnits), and that outputs its result to a researchLog.
|
|
||||||
*
|
|
||||||
* @param wordCapacity maximum number of words
|
|
||||||
*/
|
|
||||||
public FixedLogBuffer(final int wordCapacity) {
|
|
||||||
super();
|
|
||||||
if (wordCapacity <= 0) {
|
|
||||||
throw new IllegalArgumentException("wordCapacity must be 1 or greater.");
|
|
||||||
}
|
|
||||||
mWordCapacity = wordCapacity;
|
|
||||||
mNumActualWords = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new LogUnit to the front of the LIFO queue, evicting existing LogUnit's
|
|
||||||
* (oldest first) if word capacity is reached.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void shiftIn(final LogUnit newLogUnit) {
|
|
||||||
if (!newLogUnit.hasOneOrMoreWords()) {
|
|
||||||
// This LogUnit doesn't contain any word, so it doesn't count toward the word-limit.
|
|
||||||
super.shiftIn(newLogUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final int numWordsIncoming = newLogUnit.getNumWords();
|
|
||||||
if (mNumActualWords >= mWordCapacity) {
|
|
||||||
// Give subclass a chance to handle the buffer full condition by shifting out logUnits.
|
|
||||||
// TODO: Tell onBufferFull() how much space it needs to make to avoid forced eviction.
|
|
||||||
onBufferFull();
|
|
||||||
// If still full, evict.
|
|
||||||
if (mNumActualWords >= mWordCapacity) {
|
|
||||||
shiftOutWords(numWordsIncoming);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.shiftIn(newLogUnit);
|
|
||||||
mNumActualWords += numWordsIncoming;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LogUnit unshiftIn() {
|
|
||||||
final LogUnit logUnit = super.unshiftIn();
|
|
||||||
if (logUnit != null && logUnit.hasOneOrMoreWords()) {
|
|
||||||
mNumActualWords -= logUnit.getNumWords();
|
|
||||||
}
|
|
||||||
return logUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumWords() {
|
|
||||||
return mNumActualWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all LogUnits from the buffer without calling onShiftOut().
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
super.clear();
|
|
||||||
mNumActualWords = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the buffer has just shifted in one more word than its maximum, and its about to
|
|
||||||
* shift out LogUnits to bring it back down to the maximum.
|
|
||||||
*
|
|
||||||
* Base class does nothing; subclasses may override if they want to record non-privacy sensitive
|
|
||||||
* events that fall off the end.
|
|
||||||
*/
|
|
||||||
protected void onBufferFull() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LogUnit shiftOut() {
|
|
||||||
final LogUnit logUnit = super.shiftOut();
|
|
||||||
if (logUnit != null && logUnit.hasOneOrMoreWords()) {
|
|
||||||
mNumActualWords -= logUnit.getNumWords();
|
|
||||||
}
|
|
||||||
return logUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove LogUnits from the front of the LogBuffer until {@code numWords} have been removed.
|
|
||||||
*
|
|
||||||
* If there are less than {@code numWords} in the buffer, shifts out all {@code LogUnit}s.
|
|
||||||
*
|
|
||||||
* @param numWords the minimum number of words in {@link LogUnit}s to shift out
|
|
||||||
* @return the number of actual words LogUnit}s shifted out
|
|
||||||
*/
|
|
||||||
protected int shiftOutWords(final int numWords) {
|
|
||||||
int numWordsShiftedOut = 0;
|
|
||||||
do {
|
|
||||||
final LogUnit logUnit = shiftOut();
|
|
||||||
if (logUnit == null) break;
|
|
||||||
numWordsShiftedOut += logUnit.getNumWords();
|
|
||||||
} while (numWordsShiftedOut < numWords);
|
|
||||||
return numWordsShiftedOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shiftOutAll() {
|
|
||||||
final LinkedList<LogUnit> logUnits = getLogUnits();
|
|
||||||
while (!logUnits.isEmpty()) {
|
|
||||||
shiftOut();
|
|
||||||
}
|
|
||||||
mNumActualWords = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of {@link LogUnit}s at the front of the buffer that have words associated with
|
|
||||||
* them.
|
|
||||||
*
|
|
||||||
* There will be no more than {@code n} words in the returned list. So if 2 words are
|
|
||||||
* requested, and the first LogUnit has 3 words, it is not returned. If 2 words are requested,
|
|
||||||
* and the first LogUnit has only 1 word, and the next LogUnit 2 words, only the first LogUnit
|
|
||||||
* is returned. If the first LogUnit has no words associated with it, and the second LogUnit
|
|
||||||
* has three words, then only the first LogUnit (which has no associated words) is returned. If
|
|
||||||
* there are not enough LogUnits in the buffer to meet the word requirement, then all LogUnits
|
|
||||||
* will be returned.
|
|
||||||
*
|
|
||||||
* @param n The maximum number of {@link LogUnit}s with words to return.
|
|
||||||
* @return The list of the {@link LogUnit}s containing the first n words
|
|
||||||
*/
|
|
||||||
public ArrayList<LogUnit> peekAtFirstNWords(int n) {
|
|
||||||
final LinkedList<LogUnit> logUnits = getLogUnits();
|
|
||||||
// Allocate space for n*2 logUnits. There will be at least n, one for each word, and
|
|
||||||
// there may be additional for punctuation, between-word commands, etc. This should be
|
|
||||||
// enough that reallocation won't be necessary.
|
|
||||||
final ArrayList<LogUnit> resultList = new ArrayList<>(n * 2);
|
|
||||||
for (final LogUnit logUnit : logUnits) {
|
|
||||||
n -= logUnit.getNumWords();
|
|
||||||
if (n < 0) break;
|
|
||||||
resultList.add(logUnit);
|
|
||||||
}
|
|
||||||
return resultList;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.util.JsonWriter;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.inputmethod.CompletionInfo;
|
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.Key;
|
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Routines for mapping classes and variables to JSON representations for logging.
|
|
||||||
*/
|
|
||||||
/* package */ class JsonUtils {
|
|
||||||
private JsonUtils() {
|
|
||||||
// This utility class is not publicly instantiable.
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static void writeJson(final CompletionInfo[] ci, final JsonWriter jsonWriter)
|
|
||||||
throws IOException {
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
for (int j = 0; j < ci.length; j++) {
|
|
||||||
jsonWriter.value(ci[j].toString());
|
|
||||||
}
|
|
||||||
jsonWriter.endArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static void writeJson(final SharedPreferences prefs, final JsonWriter jsonWriter)
|
|
||||||
throws IOException {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
for (Map.Entry<String,?> entry : prefs.getAll().entrySet()) {
|
|
||||||
jsonWriter.name(entry.getKey());
|
|
||||||
final Object innerValue = entry.getValue();
|
|
||||||
if (innerValue == null) {
|
|
||||||
jsonWriter.nullValue();
|
|
||||||
} else if (innerValue instanceof Boolean) {
|
|
||||||
jsonWriter.value((Boolean) innerValue);
|
|
||||||
} else if (innerValue instanceof Number) {
|
|
||||||
jsonWriter.value((Number) innerValue);
|
|
||||||
} else {
|
|
||||||
jsonWriter.value(innerValue.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static void writeJson(final Key[] keys, final JsonWriter jsonWriter)
|
|
||||||
throws IOException {
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
for (Key key : keys) {
|
|
||||||
writeJson(key, jsonWriter);
|
|
||||||
}
|
|
||||||
jsonWriter.endArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeJson(final Key key, final JsonWriter jsonWriter) throws IOException {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("code").value(key.getCode());
|
|
||||||
jsonWriter.name("altCode").value(key.getAltCode());
|
|
||||||
jsonWriter.name("x").value(key.getX());
|
|
||||||
jsonWriter.name("y").value(key.getY());
|
|
||||||
jsonWriter.name("w").value(key.getWidth());
|
|
||||||
jsonWriter.name("h").value(key.getHeight());
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static void writeJson(final SuggestedWords words, final JsonWriter jsonWriter)
|
|
||||||
throws IOException {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("typedWordValid").value(words.mTypedWordValid);
|
|
||||||
jsonWriter.name("willAutoCorrect")
|
|
||||||
.value(words.mWillAutoCorrect);
|
|
||||||
jsonWriter.name("isPunctuationSuggestions")
|
|
||||||
.value(words.isPunctuationSuggestions());
|
|
||||||
jsonWriter.name("isObsoleteSuggestions").value(words.mIsObsoleteSuggestions);
|
|
||||||
jsonWriter.name("isPrediction").value(words.mIsPrediction);
|
|
||||||
jsonWriter.name("suggestedWords");
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
final int size = words.size();
|
|
||||||
for (int j = 0; j < size; j++) {
|
|
||||||
final SuggestedWordInfo wordInfo = words.getInfo(j);
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("word").value(wordInfo.toString());
|
|
||||||
jsonWriter.name("score").value(wordInfo.mScore);
|
|
||||||
jsonWriter.name("kind").value(wordInfo.getKind());
|
|
||||||
jsonWriter.name("sourceDict").value(wordInfo.mSourceDict.mDictType);
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
jsonWriter.endArray();
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static void writeJson(final MotionEvent me, final JsonWriter jsonWriter)
|
|
||||||
throws IOException {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("pointerIds");
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
final int pointerCount = me.getPointerCount();
|
|
||||||
for (int index = 0; index < pointerCount; index++) {
|
|
||||||
jsonWriter.value(me.getPointerId(index));
|
|
||||||
}
|
|
||||||
jsonWriter.endArray();
|
|
||||||
|
|
||||||
jsonWriter.name("xyt");
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
final int historicalSize = me.getHistorySize();
|
|
||||||
for (int index = 0; index < historicalSize; index++) {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("t");
|
|
||||||
jsonWriter.value(me.getHistoricalEventTime(index));
|
|
||||||
jsonWriter.name("d");
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("x");
|
|
||||||
jsonWriter.value(me.getHistoricalX(pointerIndex, index));
|
|
||||||
jsonWriter.name("y");
|
|
||||||
jsonWriter.value(me.getHistoricalY(pointerIndex, index));
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
jsonWriter.endArray();
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("t");
|
|
||||||
jsonWriter.value(me.getEventTime());
|
|
||||||
jsonWriter.name("d");
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name("x");
|
|
||||||
jsonWriter.value(me.getX(pointerIndex));
|
|
||||||
jsonWriter.name("y");
|
|
||||||
jsonWriter.value(me.getY(pointerIndex));
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
jsonWriter.endArray();
|
|
||||||
jsonWriter.endObject();
|
|
||||||
jsonWriter.endArray();
|
|
||||||
jsonWriter.endObject();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maintain a FIFO queue of LogUnits.
|
|
||||||
*
|
|
||||||
* This class provides an unbounded queue. This is useful when the user is aware that their actions
|
|
||||||
* are being recorded, such as when they are trying to reproduce a bug. In this case, there should
|
|
||||||
* not be artificial restrictions on how many events that can be saved.
|
|
||||||
*/
|
|
||||||
public class LogBuffer {
|
|
||||||
// TODO: Gracefully handle situations in which this LogBuffer is consuming too much memory.
|
|
||||||
// This may happen, for example, if the user has forgotten that data is being logged.
|
|
||||||
private final LinkedList<LogUnit> mLogUnits;
|
|
||||||
|
|
||||||
public LogBuffer() {
|
|
||||||
mLogUnits = new LinkedList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected LinkedList<LogUnit> getLogUnits() {
|
|
||||||
return mLogUnits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
mLogUnits.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shiftIn(final LogUnit logUnit) {
|
|
||||||
mLogUnits.add(logUnit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogUnit unshiftIn() {
|
|
||||||
if (mLogUnits.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return mLogUnits.removeLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogUnit peekLastLogUnit() {
|
|
||||||
if (mLogUnits.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return mLogUnits.peekLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return mLogUnits.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogUnit shiftOut() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return mLogUnits.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,225 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.util.JsonWriter;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.inputmethod.CompletionInfo;
|
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.Key;
|
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A template for typed information stored in the logs.
|
|
||||||
*
|
|
||||||
* A LogStatement contains a name, keys, and flags about whether the {@code Object[] values}
|
|
||||||
* associated with the {@code String[] keys} are likely to reveal information about the user. The
|
|
||||||
* actual values are stored separately.
|
|
||||||
*/
|
|
||||||
public class LogStatement {
|
|
||||||
private static final String TAG = LogStatement.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
|
|
||||||
// Constants for particular statements
|
|
||||||
public static final String TYPE_POINTER_TRACKER_CALL_LISTENER_ON_CODE_INPUT =
|
|
||||||
"PointerTrackerCallListenerOnCodeInput";
|
|
||||||
public static final String KEY_CODE = "code";
|
|
||||||
public static final String VALUE_RESEARCH = "research";
|
|
||||||
public static final String TYPE_MAIN_KEYBOARD_VIEW_ON_LONG_PRESS =
|
|
||||||
"MainKeyboardViewOnLongPress";
|
|
||||||
public static final String ACTION = "action";
|
|
||||||
public static final String VALUE_DOWN = "DOWN";
|
|
||||||
public static final String TYPE_MOTION_EVENT = "MotionEvent";
|
|
||||||
public static final String KEY_IS_LOGGING_RELATED = "isLoggingRelated";
|
|
||||||
|
|
||||||
// Keys for internal key/value pairs
|
|
||||||
private static final String CURRENT_TIME_KEY = "_ct";
|
|
||||||
private static final String UPTIME_KEY = "_ut";
|
|
||||||
private static final String EVENT_TYPE_KEY = "_ty";
|
|
||||||
|
|
||||||
// Name specifying the LogStatement type.
|
|
||||||
private final String mType;
|
|
||||||
|
|
||||||
// mIsPotentiallyPrivate indicates that event contains potentially private information. If
|
|
||||||
// the word that this event is a part of is determined to be privacy-sensitive, then this
|
|
||||||
// event should not be included in the output log. The system waits to output until the
|
|
||||||
// containing word is known.
|
|
||||||
private final boolean mIsPotentiallyPrivate;
|
|
||||||
|
|
||||||
// mIsPotentiallyRevealing indicates that this statement may disclose details about other
|
|
||||||
// words typed in other LogUnits. This can happen if the user is not inserting spaces, and
|
|
||||||
// data from Suggestions and/or Composing text reveals the entire "megaword". For example,
|
|
||||||
// say the user is typing "for the win", and the system wants to record the bigram "the
|
|
||||||
// win". If the user types "forthe", omitting the space, the system will give "for the" as
|
|
||||||
// a suggestion. If the user accepts the autocorrection, the suggestion for "for the" is
|
|
||||||
// included in the log for the word "the", disclosing that the previous word had been "for".
|
|
||||||
// For now, we simply do not include this data when logging part of a "megaword".
|
|
||||||
private final boolean mIsPotentiallyRevealing;
|
|
||||||
|
|
||||||
// mKeys stores the names that are the attributes in the output json objects
|
|
||||||
private final String[] mKeys;
|
|
||||||
private static final String[] NULL_KEYS = new String[0];
|
|
||||||
|
|
||||||
LogStatement(final String name, final boolean isPotentiallyPrivate,
|
|
||||||
final boolean isPotentiallyRevealing, final String... keys) {
|
|
||||||
mType = name;
|
|
||||||
mIsPotentiallyPrivate = isPotentiallyPrivate;
|
|
||||||
mIsPotentiallyRevealing = isPotentiallyRevealing;
|
|
||||||
mKeys = (keys == null) ? NULL_KEYS : keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return mType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPotentiallyPrivate() {
|
|
||||||
return mIsPotentiallyPrivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPotentiallyRevealing() {
|
|
||||||
return mIsPotentiallyRevealing;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getKeys() {
|
|
||||||
return mKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility function to test whether a key-value pair exists in a LogStatement.
|
|
||||||
*
|
|
||||||
* A LogStatement is really just a template -- it does not contain the values, only the
|
|
||||||
* keys. So the values must be passed in as an argument.
|
|
||||||
*
|
|
||||||
* @param queryKey the String that is tested by {@code String.equals()} to the keys in the
|
|
||||||
* LogStatement
|
|
||||||
* @param queryValue an Object that must be {@code Object.equals()} to the key's corresponding
|
|
||||||
* value in the {@code values} array
|
|
||||||
* @param values the values corresponding to mKeys
|
|
||||||
*
|
|
||||||
* @returns {@true} if {@code queryKey} exists in the keys for this LogStatement, and {@code
|
|
||||||
* queryValue} matches the corresponding value in {@code values}
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if {@code values.length} is not equal to keys().length()
|
|
||||||
*/
|
|
||||||
public boolean containsKeyValuePair(final String queryKey, final Object queryValue,
|
|
||||||
final Object[] values) {
|
|
||||||
if (mKeys.length != values.length) {
|
|
||||||
throw new IllegalArgumentException("Mismatched number of keys and values.");
|
|
||||||
}
|
|
||||||
final int length = mKeys.length;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
if (mKeys[i].equals(queryKey) && values[i].equals(queryValue)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility function to set a value in a LogStatement.
|
|
||||||
*
|
|
||||||
* A LogStatement is really just a template -- it does not contain the values, only the
|
|
||||||
* keys. So the values must be passed in as an argument.
|
|
||||||
*
|
|
||||||
* @param queryKey the String that is tested by {@code String.equals()} to the keys in the
|
|
||||||
* LogStatement
|
|
||||||
* @param values the array of values corresponding to mKeys
|
|
||||||
* @param newValue the replacement value to go into the {@code values} array
|
|
||||||
*
|
|
||||||
* @returns {@true} if the key exists and the value was successfully set, {@false} otherwise
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if {@code values.length} is not equal to keys().length()
|
|
||||||
*/
|
|
||||||
public boolean setValue(final String queryKey, final Object[] values, final Object newValue) {
|
|
||||||
if (mKeys.length != values.length) {
|
|
||||||
throw new IllegalArgumentException("Mismatched number of keys and values.");
|
|
||||||
}
|
|
||||||
final int length = mKeys.length;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
if (mKeys[i].equals(queryKey)) {
|
|
||||||
values[i] = newValue;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the contents out through jsonWriter.
|
|
||||||
*
|
|
||||||
* The JsonWriter class must have already had {@code JsonWriter.beginArray} called on it.
|
|
||||||
*
|
|
||||||
* Note that this method is not thread safe for the same jsonWriter. Callers must ensure
|
|
||||||
* thread safety.
|
|
||||||
*/
|
|
||||||
public boolean outputToLocked(final JsonWriter jsonWriter, final Long time,
|
|
||||||
final Object... values) {
|
|
||||||
if (DEBUG) {
|
|
||||||
if (mKeys.length != values.length) {
|
|
||||||
Log.d(TAG, "Key and Value list sizes do not match. " + mType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
jsonWriter.beginObject();
|
|
||||||
jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
|
|
||||||
jsonWriter.name(UPTIME_KEY).value(time);
|
|
||||||
jsonWriter.name(EVENT_TYPE_KEY).value(mType);
|
|
||||||
final int length = values.length;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
jsonWriter.name(mKeys[i]);
|
|
||||||
final Object value = values[i];
|
|
||||||
if (value instanceof CharSequence) {
|
|
||||||
jsonWriter.value(value.toString());
|
|
||||||
} else if (value instanceof Number) {
|
|
||||||
jsonWriter.value((Number) value);
|
|
||||||
} else if (value instanceof Boolean) {
|
|
||||||
jsonWriter.value((Boolean) value);
|
|
||||||
} else if (value instanceof CompletionInfo[]) {
|
|
||||||
JsonUtils.writeJson((CompletionInfo[]) value, jsonWriter);
|
|
||||||
} else if (value instanceof SharedPreferences) {
|
|
||||||
JsonUtils.writeJson((SharedPreferences) value, jsonWriter);
|
|
||||||
} else if (value instanceof Key[]) {
|
|
||||||
JsonUtils.writeJson((Key[]) value, jsonWriter);
|
|
||||||
} else if (value instanceof SuggestedWords) {
|
|
||||||
JsonUtils.writeJson((SuggestedWords) value, jsonWriter);
|
|
||||||
} else if (value instanceof MotionEvent) {
|
|
||||||
JsonUtils.writeJson((MotionEvent) value, jsonWriter);
|
|
||||||
} else if (value == null) {
|
|
||||||
jsonWriter.nullValue();
|
|
||||||
} else {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Unrecognized type to be logged: "
|
|
||||||
+ (value == null ? "<null>" : value.getClass().getName()));
|
|
||||||
}
|
|
||||||
jsonWriter.nullValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonWriter.endObject();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
Log.w(TAG, "Error in JsonWriter; skipping LogStatement");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,496 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.JsonWriter;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A group of log statements related to each other.
|
|
||||||
*
|
|
||||||
* A LogUnit is collection of LogStatements, each of which is generated by at a particular point
|
|
||||||
* in the code. (There is no LogStatement class; the data is stored across the instance variables
|
|
||||||
* here.) A single LogUnit's statements can correspond to all the calls made while in the same
|
|
||||||
* composing region, or all the calls between committing the last composing region, and the first
|
|
||||||
* character of the next composing region.
|
|
||||||
*
|
|
||||||
* Individual statements in a log may be marked as potentially private. If so, then they are only
|
|
||||||
* published to a ResearchLog if the ResearchLogger determines that publishing the entire LogUnit
|
|
||||||
* will not violate the user's privacy. Checks for this may include whether other LogUnits have
|
|
||||||
* been published recently, or whether the LogUnit contains numbers, etc.
|
|
||||||
*/
|
|
||||||
public class LogUnit {
|
|
||||||
private static final String TAG = LogUnit.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
|
|
||||||
private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+");
|
|
||||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
|
||||||
|
|
||||||
private final ArrayList<LogStatement> mLogStatementList;
|
|
||||||
private final ArrayList<Object[]> mValuesList;
|
|
||||||
// Assume that mTimeList is sorted in increasing order. Do not insert null values into
|
|
||||||
// mTimeList.
|
|
||||||
private final ArrayList<Long> mTimeList;
|
|
||||||
// Words that this LogUnit generates. Should be null if the data in the LogUnit does not
|
|
||||||
// generate a genuine word (i.e. separators alone do not count as a word). Should never be
|
|
||||||
// empty. Note that if the user types spaces explicitly, then normally mWords should contain
|
|
||||||
// only a single word; it will only contain space-separate multiple words if the user does not
|
|
||||||
// enter a space, and the system enters one automatically.
|
|
||||||
private String mWords;
|
|
||||||
private String[] mWordArray = EMPTY_STRING_ARRAY;
|
|
||||||
private boolean mMayContainDigit;
|
|
||||||
private boolean mIsPartOfMegaword;
|
|
||||||
private boolean mContainsUserDeletions;
|
|
||||||
|
|
||||||
// mCorrectionType indicates whether the word was corrected at all, and if so, the nature of the
|
|
||||||
// correction.
|
|
||||||
private int mCorrectionType;
|
|
||||||
// LogUnits start in this state. If a word is entered without being corrected, it will have
|
|
||||||
// this CorrectiontType.
|
|
||||||
public static final int CORRECTIONTYPE_NO_CORRECTION = 0;
|
|
||||||
// The LogUnit was corrected manually by the user in an unspecified way.
|
|
||||||
public static final int CORRECTIONTYPE_CORRECTION = 1;
|
|
||||||
// The LogUnit was corrected manually by the user to a word not in the list of suggestions of
|
|
||||||
// the first word typed here. (Note: this is a heuristic value, it may be incorrect, for
|
|
||||||
// example, if the user repositions the cursor).
|
|
||||||
public static final int CORRECTIONTYPE_DIFFERENT_WORD = 2;
|
|
||||||
// The LogUnit was corrected manually by the user to a word that was in the list of suggestions
|
|
||||||
// of the first word typed here. (Again, a heuristic). It is probably a typo correction.
|
|
||||||
public static final int CORRECTIONTYPE_TYPO = 3;
|
|
||||||
// TODO: Rather than just tracking the current state, keep a historical record of the LogUnit's
|
|
||||||
// state and statistics. This should include how many times it has been corrected, whether
|
|
||||||
// other LogUnit edits were done between edits to this LogUnit, etc. Also track when a LogUnit
|
|
||||||
// previously contained a word, but was corrected to empty (because it was deleted, and there is
|
|
||||||
// no known replacement).
|
|
||||||
|
|
||||||
private SuggestedWords mSuggestedWords;
|
|
||||||
|
|
||||||
public LogUnit() {
|
|
||||||
mLogStatementList = new ArrayList<>();
|
|
||||||
mValuesList = new ArrayList<>();
|
|
||||||
mTimeList = new ArrayList<>();
|
|
||||||
mIsPartOfMegaword = false;
|
|
||||||
mCorrectionType = CORRECTIONTYPE_NO_CORRECTION;
|
|
||||||
mSuggestedWords = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogUnit(final ArrayList<LogStatement> logStatementList,
|
|
||||||
final ArrayList<Object[]> valuesList,
|
|
||||||
final ArrayList<Long> timeList,
|
|
||||||
final boolean isPartOfMegaword) {
|
|
||||||
mLogStatementList = logStatementList;
|
|
||||||
mValuesList = valuesList;
|
|
||||||
mTimeList = timeList;
|
|
||||||
mIsPartOfMegaword = isPartOfMegaword;
|
|
||||||
mCorrectionType = CORRECTIONTYPE_NO_CORRECTION;
|
|
||||||
mSuggestedWords = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Object[] NULL_VALUES = new Object[0];
|
|
||||||
/**
|
|
||||||
* Adds a new log statement. The time parameter in successive calls to this method must be
|
|
||||||
* monotonically increasing, or splitByTime() will not work.
|
|
||||||
*/
|
|
||||||
public void addLogStatement(final LogStatement logStatement, final long time,
|
|
||||||
Object... values) {
|
|
||||||
if (values == null) {
|
|
||||||
values = NULL_VALUES;
|
|
||||||
}
|
|
||||||
mLogStatementList.add(logStatement);
|
|
||||||
mValuesList.add(values);
|
|
||||||
mTimeList.add(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publish the contents of this LogUnit to {@code researchLog}.
|
|
||||||
*
|
|
||||||
* For each publishable {@code LogStatement}, invoke {@link LogStatement#outputToLocked}.
|
|
||||||
*
|
|
||||||
* @param researchLog where to publish the contents of this {@code LogUnit}
|
|
||||||
* @param canIncludePrivateData whether the private data in this {@code LogUnit} should be
|
|
||||||
* included
|
|
||||||
*
|
|
||||||
* @throws IOException if publication to the log file is not possible
|
|
||||||
*/
|
|
||||||
public synchronized void publishTo(final ResearchLog researchLog,
|
|
||||||
final boolean canIncludePrivateData) throws IOException {
|
|
||||||
// Write out any logStatement that passes the privacy filter.
|
|
||||||
final int size = mLogStatementList.size();
|
|
||||||
if (size != 0) {
|
|
||||||
// Note that jsonWriter is only set to a non-null value if the logUnit start text is
|
|
||||||
// output and at least one logStatement is output.
|
|
||||||
JsonWriter jsonWriter = researchLog.getInitializedJsonWriterLocked();
|
|
||||||
outputLogUnitStart(jsonWriter, canIncludePrivateData);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
final LogStatement logStatement = mLogStatementList.get(i);
|
|
||||||
if (!canIncludePrivateData && logStatement.isPotentiallyPrivate()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (mIsPartOfMegaword && logStatement.isPotentiallyRevealing()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
logStatement.outputToLocked(jsonWriter, mTimeList.get(i), mValuesList.get(i));
|
|
||||||
}
|
|
||||||
outputLogUnitStop(jsonWriter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String WORD_KEY = "_wo";
|
|
||||||
private static final String NUM_WORDS_KEY = "_nw";
|
|
||||||
private static final String CORRECTION_TYPE_KEY = "_corType";
|
|
||||||
private static final String LOG_UNIT_BEGIN_KEY = "logUnitStart";
|
|
||||||
private static final String LOG_UNIT_END_KEY = "logUnitEnd";
|
|
||||||
|
|
||||||
final LogStatement LOGSTATEMENT_LOG_UNIT_BEGIN_WITH_PRIVATE_DATA =
|
|
||||||
new LogStatement(LOG_UNIT_BEGIN_KEY, false /* isPotentiallyPrivate */,
|
|
||||||
false /* isPotentiallyRevealing */, WORD_KEY, CORRECTION_TYPE_KEY,
|
|
||||||
NUM_WORDS_KEY);
|
|
||||||
final LogStatement LOGSTATEMENT_LOG_UNIT_BEGIN_WITHOUT_PRIVATE_DATA =
|
|
||||||
new LogStatement(LOG_UNIT_BEGIN_KEY, false /* isPotentiallyPrivate */,
|
|
||||||
false /* isPotentiallyRevealing */, NUM_WORDS_KEY);
|
|
||||||
private void outputLogUnitStart(final JsonWriter jsonWriter,
|
|
||||||
final boolean canIncludePrivateData) {
|
|
||||||
final LogStatement logStatement;
|
|
||||||
if (canIncludePrivateData) {
|
|
||||||
LOGSTATEMENT_LOG_UNIT_BEGIN_WITH_PRIVATE_DATA.outputToLocked(jsonWriter,
|
|
||||||
SystemClock.uptimeMillis(), getWordsAsString(), getCorrectionType(),
|
|
||||||
getNumWords());
|
|
||||||
} else {
|
|
||||||
LOGSTATEMENT_LOG_UNIT_BEGIN_WITHOUT_PRIVATE_DATA.outputToLocked(jsonWriter,
|
|
||||||
SystemClock.uptimeMillis(), getNumWords());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final LogStatement LOGSTATEMENT_LOG_UNIT_END =
|
|
||||||
new LogStatement(LOG_UNIT_END_KEY, false /* isPotentiallyPrivate */,
|
|
||||||
false /* isPotentiallyRevealing */);
|
|
||||||
private void outputLogUnitStop(final JsonWriter jsonWriter) {
|
|
||||||
LOGSTATEMENT_LOG_UNIT_END.outputToLocked(jsonWriter, SystemClock.uptimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark the current logUnit as containing data to generate {@code newWords}.
|
|
||||||
*
|
|
||||||
* If {@code setWord()} was previously called for this LogUnit, then the method will try to
|
|
||||||
* determine what kind of correction it is, and update its internal state of the correctionType
|
|
||||||
* accordingly.
|
|
||||||
*
|
|
||||||
* @param newWords The words this LogUnit generates. Caller should not pass null or the empty
|
|
||||||
* string.
|
|
||||||
*/
|
|
||||||
public void setWords(final String newWords) {
|
|
||||||
if (hasOneOrMoreWords()) {
|
|
||||||
// The word was already set once, and it is now being changed. See if the new word
|
|
||||||
// is close to the old word. If so, then the change is probably a typo correction.
|
|
||||||
// If not, the user may have decided to enter a different word, so flag it.
|
|
||||||
if (mSuggestedWords != null) {
|
|
||||||
if (isInSuggestedWords(newWords, mSuggestedWords)) {
|
|
||||||
mCorrectionType = CORRECTIONTYPE_TYPO;
|
|
||||||
} else {
|
|
||||||
mCorrectionType = CORRECTIONTYPE_DIFFERENT_WORD;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No suggested words, so it's not clear whether it's a typo or different word.
|
|
||||||
// Mark it as a generic correction.
|
|
||||||
mCorrectionType = CORRECTIONTYPE_CORRECTION;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mCorrectionType = CORRECTIONTYPE_NO_CORRECTION;
|
|
||||||
}
|
|
||||||
mWords = newWords;
|
|
||||||
|
|
||||||
// Update mWordArray
|
|
||||||
mWordArray = (TextUtils.isEmpty(mWords)) ? EMPTY_STRING_ARRAY
|
|
||||||
: WHITESPACE_PATTERN.split(mWords);
|
|
||||||
if (mWordArray.length > 0 && TextUtils.isEmpty(mWordArray[0])) {
|
|
||||||
// Empty string at beginning of array. Must have been whitespace at the start of the
|
|
||||||
// word. Remove the empty string.
|
|
||||||
mWordArray = Arrays.copyOfRange(mWordArray, 1, mWordArray.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWordsAsString() {
|
|
||||||
return mWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retuns the words generated by the data in this LogUnit.
|
|
||||||
*
|
|
||||||
* The first word may be an empty string, if the data in the LogUnit started by generating
|
|
||||||
* whitespace.
|
|
||||||
*
|
|
||||||
* @return the array of words. an empty list of there are no words associated with this LogUnit.
|
|
||||||
*/
|
|
||||||
public String[] getWordsAsStringArray() {
|
|
||||||
return mWordArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasOneOrMoreWords() {
|
|
||||||
return mWordArray.length >= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumWords() {
|
|
||||||
return mWordArray.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor to eliminate getter/setters
|
|
||||||
public void setMayContainDigit() {
|
|
||||||
mMayContainDigit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor to eliminate getter/setters
|
|
||||||
public boolean mayContainDigit() {
|
|
||||||
return mMayContainDigit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor to eliminate getter/setters
|
|
||||||
public void setContainsUserDeletions() {
|
|
||||||
mContainsUserDeletions = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor to eliminate getter/setters
|
|
||||||
public boolean containsUserDeletions() {
|
|
||||||
return mContainsUserDeletions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor to eliminate getter/setters
|
|
||||||
public void setCorrectionType(final int correctionType) {
|
|
||||||
mCorrectionType = correctionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor to eliminate getter/setters
|
|
||||||
public int getCorrectionType() {
|
|
||||||
return mCorrectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return mLogStatementList.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split this logUnit, with all events before maxTime staying in the current logUnit, and all
|
|
||||||
* events after maxTime going into a new LogUnit that is returned.
|
|
||||||
*/
|
|
||||||
public LogUnit splitByTime(final long maxTime) {
|
|
||||||
// Assume that mTimeList is in sorted order.
|
|
||||||
final int length = mTimeList.size();
|
|
||||||
// TODO: find time by binary search, e.g. using Collections#binarySearch()
|
|
||||||
for (int index = 0; index < length; index++) {
|
|
||||||
if (mTimeList.get(index) > maxTime) {
|
|
||||||
final List<LogStatement> laterLogStatements =
|
|
||||||
mLogStatementList.subList(index, length);
|
|
||||||
final List<Object[]> laterValues = mValuesList.subList(index, length);
|
|
||||||
final List<Long> laterTimes = mTimeList.subList(index, length);
|
|
||||||
|
|
||||||
// Create the LogUnit containing the later logStatements and associated data.
|
|
||||||
final LogUnit newLogUnit = new LogUnit(
|
|
||||||
new ArrayList<>(laterLogStatements),
|
|
||||||
new ArrayList<>(laterValues),
|
|
||||||
new ArrayList<>(laterTimes),
|
|
||||||
true /* isPartOfMegaword */);
|
|
||||||
newLogUnit.mWords = null;
|
|
||||||
newLogUnit.mMayContainDigit = mMayContainDigit;
|
|
||||||
newLogUnit.mContainsUserDeletions = mContainsUserDeletions;
|
|
||||||
|
|
||||||
// Purge the logStatements and associated data from this LogUnit.
|
|
||||||
laterLogStatements.clear();
|
|
||||||
laterValues.clear();
|
|
||||||
laterTimes.clear();
|
|
||||||
mIsPartOfMegaword = true;
|
|
||||||
|
|
||||||
return newLogUnit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new LogUnit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void append(final LogUnit logUnit) {
|
|
||||||
mLogStatementList.addAll(logUnit.mLogStatementList);
|
|
||||||
mValuesList.addAll(logUnit.mValuesList);
|
|
||||||
mTimeList.addAll(logUnit.mTimeList);
|
|
||||||
mWords = null;
|
|
||||||
if (logUnit.mWords != null) {
|
|
||||||
setWords(logUnit.mWords);
|
|
||||||
}
|
|
||||||
mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit;
|
|
||||||
mContainsUserDeletions = mContainsUserDeletions || logUnit.mContainsUserDeletions;
|
|
||||||
mIsPartOfMegaword = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SuggestedWords getSuggestions() {
|
|
||||||
return mSuggestedWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the suggestions.
|
|
||||||
*
|
|
||||||
* Once set to a non-null value, the suggestions may not be changed again. This is to keep
|
|
||||||
* track of the list of words that are close to the user's initial effort to type the word.
|
|
||||||
* Only words that are close to the initial effort are considered typo corrections.
|
|
||||||
*/
|
|
||||||
public void initializeSuggestions(final SuggestedWords suggestedWords) {
|
|
||||||
if (mSuggestedWords == null) {
|
|
||||||
mSuggestedWords = suggestedWords;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isInSuggestedWords(final String queryWord,
|
|
||||||
final SuggestedWords suggestedWords) {
|
|
||||||
if (TextUtils.isEmpty(queryWord)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final int size = suggestedWords.size();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
final SuggestedWordInfo wordInfo = suggestedWords.getInfo(i);
|
|
||||||
if (queryWord.equals(wordInfo.mWord)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove data associated with selecting the Research button.
|
|
||||||
*
|
|
||||||
* A LogUnit will capture all user interactions with the IME, including the "meta-interactions"
|
|
||||||
* of using the Research button to control the logging (e.g. by starting and stopping recording
|
|
||||||
* of a test case). Because meta-interactions should not be part of the normal log, calling
|
|
||||||
* this method will set a field in the LogStatements of the motion events to indiciate that
|
|
||||||
* they should be disregarded.
|
|
||||||
*
|
|
||||||
* This implementation assumes that the data recorded by the meta-interaction takes the
|
|
||||||
* form of all events following the first MotionEvent.ACTION_DOWN before the first long-press
|
|
||||||
* before the last onCodeEvent containing a code matching {@code LogStatement.VALUE_RESEARCH}.
|
|
||||||
*
|
|
||||||
* @returns true if data was removed
|
|
||||||
*/
|
|
||||||
public boolean removeResearchButtonInvocation() {
|
|
||||||
// This method is designed to be idempotent.
|
|
||||||
|
|
||||||
// First, find last invocation of "research" key
|
|
||||||
final int indexOfLastResearchKey = findLastIndexContainingKeyValue(
|
|
||||||
LogStatement.TYPE_POINTER_TRACKER_CALL_LISTENER_ON_CODE_INPUT,
|
|
||||||
LogStatement.KEY_CODE, LogStatement.VALUE_RESEARCH);
|
|
||||||
if (indexOfLastResearchKey < 0) {
|
|
||||||
// Could not find invocation of "research" key. Leave log as is.
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Could not find research key");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for the long press that started the invocation of the research key code input.
|
|
||||||
final int indexOfLastLongPressBeforeResearchKey =
|
|
||||||
findLastIndexBefore(LogStatement.TYPE_MAIN_KEYBOARD_VIEW_ON_LONG_PRESS,
|
|
||||||
indexOfLastResearchKey);
|
|
||||||
|
|
||||||
// Look for DOWN event preceding the long press
|
|
||||||
final int indexOfLastDownEventBeforeLongPress =
|
|
||||||
findLastIndexContainingKeyValueBefore(LogStatement.TYPE_MOTION_EVENT,
|
|
||||||
LogStatement.ACTION, LogStatement.VALUE_DOWN,
|
|
||||||
indexOfLastLongPressBeforeResearchKey);
|
|
||||||
|
|
||||||
// Flag all LatinKeyboardViewProcessMotionEvents from the DOWN event to the research key as
|
|
||||||
// logging-related
|
|
||||||
final int startingIndex = indexOfLastDownEventBeforeLongPress == -1 ? 0
|
|
||||||
: indexOfLastDownEventBeforeLongPress;
|
|
||||||
for (int index = startingIndex; index < indexOfLastResearchKey; index++) {
|
|
||||||
final LogStatement logStatement = mLogStatementList.get(index);
|
|
||||||
final String type = logStatement.getType();
|
|
||||||
final Object[] values = mValuesList.get(index);
|
|
||||||
if (type.equals(LogStatement.TYPE_MOTION_EVENT)) {
|
|
||||||
logStatement.setValue(LogStatement.KEY_IS_LOGGING_RELATED, values, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the index of the last LogStatement before {@code startingIndex} of type {@code type}.
|
|
||||||
*
|
|
||||||
* @param queryType a String that must be {@code String.equals()} to the LogStatement type
|
|
||||||
* @param startingIndex the index to start the backward search from. Must be less than the
|
|
||||||
* length of mLogStatementList, or an IndexOutOfBoundsException is thrown. Can be negative,
|
|
||||||
* in which case -1 is returned.
|
|
||||||
*
|
|
||||||
* @return The index of the last LogStatement, -1 if none exists.
|
|
||||||
*/
|
|
||||||
private int findLastIndexBefore(final String queryType, final int startingIndex) {
|
|
||||||
return findLastIndexContainingKeyValueBefore(queryType, null, null, startingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the index of the last LogStatement before {@code startingIndex} of type {@code type}
|
|
||||||
* containing the given key-value pair.
|
|
||||||
*
|
|
||||||
* @param queryType a String that must be {@code String.equals()} to the LogStatement type
|
|
||||||
* @param queryKey a String that must be {@code String.equals()} to a key in the LogStatement
|
|
||||||
* @param queryValue an Object that must be {@code String.equals()} to the key's corresponding
|
|
||||||
* value
|
|
||||||
*
|
|
||||||
* @return The index of the last LogStatement, -1 if none exists.
|
|
||||||
*/
|
|
||||||
private int findLastIndexContainingKeyValue(final String queryType, final String queryKey,
|
|
||||||
final Object queryValue) {
|
|
||||||
return findLastIndexContainingKeyValueBefore(queryType, queryKey, queryValue,
|
|
||||||
mLogStatementList.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the index of the last LogStatement before {@code startingIndex} of type {@code type}
|
|
||||||
* containing the given key-value pair.
|
|
||||||
*
|
|
||||||
* @param queryType a String that must be {@code String.equals()} to the LogStatement type
|
|
||||||
* @param queryKey a String that must be {@code String.equals()} to a key in the LogStatement
|
|
||||||
* @param queryValue an Object that must be {@code String.equals()} to the key's corresponding
|
|
||||||
* value
|
|
||||||
* @param startingIndex the index to start the backward search from. Must be less than the
|
|
||||||
* length of mLogStatementList, or an IndexOutOfBoundsException is thrown. Can be negative,
|
|
||||||
* in which case -1 is returned.
|
|
||||||
*
|
|
||||||
* @return The index of the last LogStatement, -1 if none exists.
|
|
||||||
*/
|
|
||||||
private int findLastIndexContainingKeyValueBefore(final String queryType, final String queryKey,
|
|
||||||
final Object queryValue, final int startingIndex) {
|
|
||||||
if (startingIndex < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for (int index = startingIndex; index >= 0; index--) {
|
|
||||||
final LogStatement logStatement = mLogStatementList.get(index);
|
|
||||||
final String type = logStatement.getType();
|
|
||||||
if (type.equals(queryType) && (queryKey == null
|
|
||||||
|| logStatement.containsKeyValuePair(queryKey, queryValue,
|
|
||||||
mValuesList.get(index)))) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
/* package */ class LoggingUtils {
|
|
||||||
private LoggingUtils() {
|
|
||||||
// This utility class is not publicly instantiable.
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static String getMotionEventActionTypeString(final int actionType) {
|
|
||||||
switch (actionType) {
|
|
||||||
case MotionEvent.ACTION_CANCEL: return "CANCEL";
|
|
||||||
case MotionEvent.ACTION_UP: return "UP";
|
|
||||||
case MotionEvent.ACTION_DOWN: return "DOWN";
|
|
||||||
case MotionEvent.ACTION_POINTER_UP: return "POINTER_UP";
|
|
||||||
case MotionEvent.ACTION_POINTER_DOWN: return "POINTER_DOWN";
|
|
||||||
case MotionEvent.ACTION_MOVE: return "MOVE";
|
|
||||||
case MotionEvent.ACTION_OUTSIDE: return "OUTSIDE";
|
|
||||||
default: return "ACTION_" + actionType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,287 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
|
||||||
import com.android.inputmethod.latin.Dictionary;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitator;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MainLogBuffer is a FixedLogBuffer that tracks the state of LogUnits to make privacy guarantees.
|
|
||||||
*
|
|
||||||
* There are three forms of privacy protection: 1) only words in the main dictionary are allowed to
|
|
||||||
* be logged in enough detail to determine their contents, 2) only a subset of words are logged
|
|
||||||
* in detail, such as 10%, and 3) no numbers are logged.
|
|
||||||
*
|
|
||||||
* This class maintains a list of LogUnits, each corresponding to a word. As the user completes
|
|
||||||
* words, they are added here. But if the user backs up over their current word to edit a word
|
|
||||||
* entered earlier, then it is pulled out of this LogBuffer, changes are then added to the end of
|
|
||||||
* the LogUnit, and it is pushed back in here when the user is done. Because words may be pulled
|
|
||||||
* back out even after they are pushed in, we must not publish the contents of this LogBuffer too
|
|
||||||
* quickly. However, we cannot let the contents pile up either, or it will limit the editing that
|
|
||||||
* a user can perform.
|
|
||||||
*
|
|
||||||
* To balance these requirements (keep history so user can edit, flush history so it does not pile
|
|
||||||
* up), the LogBuffer is considered "complete" when the user has entered enough words to form an
|
|
||||||
* n-gram, followed by enough additional non-detailed words (that are in the 90%, as per above).
|
|
||||||
* Once complete, the n-gram may be published to flash storage (via the ResearchLog class).
|
|
||||||
* However, the additional non-detailed words are retained, in case the user backspaces to edit
|
|
||||||
* them. The MainLogBuffer then continues to add words, publishing individual non-detailed words
|
|
||||||
* as new words arrive. After enough non-detailed words have been pushed out to account for the
|
|
||||||
* 90% between words, the words at the front of the LogBuffer can be published as an n-gram again.
|
|
||||||
*
|
|
||||||
* If the words that would form the valid n-gram are not in the dictionary, then words are pushed
|
|
||||||
* through the LogBuffer one at a time until an n-gram is found that is entirely composed of
|
|
||||||
* dictionary words.
|
|
||||||
*
|
|
||||||
* If the user closes a session, then the entire LogBuffer is flushed, publishing any embedded
|
|
||||||
* n-gram containing dictionary words.
|
|
||||||
*/
|
|
||||||
public abstract class MainLogBuffer extends FixedLogBuffer {
|
|
||||||
private static final String TAG = MainLogBuffer.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
|
|
||||||
// Keep consistent with switch statement in Statistics.recordPublishabilityResultCode()
|
|
||||||
public static final int PUBLISHABILITY_PUBLISHABLE = 0;
|
|
||||||
public static final int PUBLISHABILITY_UNPUBLISHABLE_STOPPING = 1;
|
|
||||||
public static final int PUBLISHABILITY_UNPUBLISHABLE_INCORRECT_WORD_COUNT = 2;
|
|
||||||
public static final int PUBLISHABILITY_UNPUBLISHABLE_SAMPLED_TOO_RECENTLY = 3;
|
|
||||||
public static final int PUBLISHABILITY_UNPUBLISHABLE_DICTIONARY_UNAVAILABLE = 4;
|
|
||||||
public static final int PUBLISHABILITY_UNPUBLISHABLE_MAY_CONTAIN_DIGIT = 5;
|
|
||||||
public static final int PUBLISHABILITY_UNPUBLISHABLE_NOT_IN_DICTIONARY = 6;
|
|
||||||
|
|
||||||
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
|
|
||||||
public static final int N_GRAM_SIZE = 2;
|
|
||||||
|
|
||||||
private final DictionaryFacilitator mDictionaryFacilitator;
|
|
||||||
@UsedForTesting
|
|
||||||
private Dictionary mDictionaryForTesting;
|
|
||||||
private boolean mIsStopping = false;
|
|
||||||
|
|
||||||
/* package for test */ int mNumWordsBetweenNGrams;
|
|
||||||
|
|
||||||
// Counter for words left to suppress before an n-gram can be sampled. Reset to mMinWordPeriod
|
|
||||||
// after a sample is taken.
|
|
||||||
/* package for test */ int mNumWordsUntilSafeToSample;
|
|
||||||
|
|
||||||
public MainLogBuffer(final int wordsBetweenSamples, final int numInitialWordsToIgnore,
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator) {
|
|
||||||
super(N_GRAM_SIZE + wordsBetweenSamples);
|
|
||||||
mNumWordsBetweenNGrams = wordsBetweenSamples;
|
|
||||||
mNumWordsUntilSafeToSample = DEBUG ? 0 : numInitialWordsToIgnore;
|
|
||||||
mDictionaryFacilitator = dictionaryFacilitator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
/* package for test */ void setDictionaryForTesting(final Dictionary dictionary) {
|
|
||||||
mDictionaryForTesting = dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidDictWord(final String word) {
|
|
||||||
if (mDictionaryForTesting != null) {
|
|
||||||
return mDictionaryForTesting.isValidWord(word);
|
|
||||||
}
|
|
||||||
if (mDictionaryFacilitator != null) {
|
|
||||||
return mDictionaryFacilitator.isValidMainDictWord(word);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsStopping() {
|
|
||||||
mIsStopping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the string determined by a series of LogUnits will not violate user
|
|
||||||
* privacy if published.
|
|
||||||
*
|
|
||||||
* @param logUnits a LogUnit list to check for publishability
|
|
||||||
* @param nGramSize the smallest n-gram acceptable to be published. if
|
|
||||||
* {@link ResearchLogger#IS_LOGGING_EVERYTHING} is true, then publish if there are more than
|
|
||||||
* {@code minNGramSize} words in the logUnits, otherwise wait. if {@link
|
|
||||||
* ResearchLogger#IS_LOGGING_EVERYTHING} is false, then ensure that there are exactly nGramSize
|
|
||||||
* words in the LogUnits.
|
|
||||||
*
|
|
||||||
* @return one of the {@code PUBLISHABILITY_*} result codes defined in this class.
|
|
||||||
*/
|
|
||||||
private int getPublishabilityResultCode(final ArrayList<LogUnit> logUnits,
|
|
||||||
final int nGramSize) {
|
|
||||||
// Bypass privacy checks when debugging.
|
|
||||||
if (ResearchLogger.IS_LOGGING_EVERYTHING) {
|
|
||||||
if (mIsStopping) {
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_STOPPING;
|
|
||||||
}
|
|
||||||
// Only check that it is the right length. If not, wait for later words to make
|
|
||||||
// complete n-grams.
|
|
||||||
int numWordsInLogUnitList = 0;
|
|
||||||
final int length = logUnits.size();
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
final LogUnit logUnit = logUnits.get(i);
|
|
||||||
numWordsInLogUnitList += logUnit.getNumWords();
|
|
||||||
}
|
|
||||||
if (numWordsInLogUnitList >= nGramSize) {
|
|
||||||
return PUBLISHABILITY_PUBLISHABLE;
|
|
||||||
} else {
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_INCORRECT_WORD_COUNT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we are not sampling too frequently. Having sampled recently might disclose
|
|
||||||
// too much of the user's intended meaning.
|
|
||||||
if (mNumWordsUntilSafeToSample > 0) {
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_SAMPLED_TOO_RECENTLY;
|
|
||||||
}
|
|
||||||
// Reload the dictionary in case it has changed (e.g., because the user has changed
|
|
||||||
// languages).
|
|
||||||
if ((mDictionaryFacilitator == null
|
|
||||||
|| !mDictionaryFacilitator.hasInitializedMainDictionary())
|
|
||||||
&& mDictionaryForTesting == null) {
|
|
||||||
// Main dictionary is unavailable. Since we cannot check it, we cannot tell if a
|
|
||||||
// word is out-of-vocabulary or not. Therefore, we must judge the entire buffer
|
|
||||||
// contents to potentially pose a privacy risk.
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_DICTIONARY_UNAVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check each word in the buffer. If any word poses a privacy threat, we cannot upload
|
|
||||||
// the complete buffer contents in detail.
|
|
||||||
int numWordsInLogUnitList = 0;
|
|
||||||
for (final LogUnit logUnit : logUnits) {
|
|
||||||
if (!logUnit.hasOneOrMoreWords()) {
|
|
||||||
// Digits outside words are a privacy threat.
|
|
||||||
if (logUnit.mayContainDigit()) {
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_MAY_CONTAIN_DIGIT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
numWordsInLogUnitList += logUnit.getNumWords();
|
|
||||||
final String[] words = logUnit.getWordsAsStringArray();
|
|
||||||
for (final String word : words) {
|
|
||||||
// Words not in the dictionary are a privacy threat.
|
|
||||||
if (ResearchLogger.hasLetters(word) && !isValidDictWord(word)) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "\"" + word + "\" NOT SAFE!: hasLetters: "
|
|
||||||
+ ResearchLogger.hasLetters(word)
|
|
||||||
+ ", isValid: " + isValidDictWord(word));
|
|
||||||
}
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_NOT_IN_DICTIONARY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, only return true if the ngram is the right size.
|
|
||||||
if (numWordsInLogUnitList == nGramSize) {
|
|
||||||
return PUBLISHABILITY_PUBLISHABLE;
|
|
||||||
} else {
|
|
||||||
return PUBLISHABILITY_UNPUBLISHABLE_INCORRECT_WORD_COUNT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shiftAndPublishAll() throws IOException {
|
|
||||||
final LinkedList<LogUnit> logUnits = getLogUnits();
|
|
||||||
while (!logUnits.isEmpty()) {
|
|
||||||
publishLogUnitsAtFrontOfBuffer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void onBufferFull() {
|
|
||||||
try {
|
|
||||||
publishLogUnitsAtFrontOfBuffer();
|
|
||||||
} catch (final IOException e) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "IOException when publishing front of LogBuffer", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If there is a safe n-gram at the front of this log buffer, publish it with all details, and
|
|
||||||
* remove the LogUnits that constitute it.
|
|
||||||
*
|
|
||||||
* An n-gram might not be "safe" if it violates privacy controls. E.g., it might contain
|
|
||||||
* numbers, an out-of-vocabulary word, or another n-gram may have been published recently. If
|
|
||||||
* there is no safe n-gram, then the LogUnits up through the first word-containing LogUnit are
|
|
||||||
* published, but without disclosing any privacy-related details, such as the word the LogUnit
|
|
||||||
* generated, motion data, etc.
|
|
||||||
*
|
|
||||||
* Note that a LogUnit can hold more than one word if the user types without explicit spaces.
|
|
||||||
* In this case, the words may be grouped together in such a way that pulling an n-gram off the
|
|
||||||
* front would require splitting a LogUnit. Splitting a LogUnit is not possible, so this case
|
|
||||||
* is treated just as the unsafe n-gram case. This may cause n-grams to be sampled at slightly
|
|
||||||
* less than the target frequency.
|
|
||||||
*/
|
|
||||||
protected final void publishLogUnitsAtFrontOfBuffer() throws IOException {
|
|
||||||
// TODO: Refactor this method to require fewer passes through the LogUnits. Should really
|
|
||||||
// require only one pass.
|
|
||||||
ArrayList<LogUnit> logUnits = peekAtFirstNWords(N_GRAM_SIZE);
|
|
||||||
final int publishabilityResultCode = getPublishabilityResultCode(logUnits, N_GRAM_SIZE);
|
|
||||||
ResearchLogger.recordPublishabilityResultCode(publishabilityResultCode);
|
|
||||||
if (publishabilityResultCode == MainLogBuffer.PUBLISHABILITY_PUBLISHABLE) {
|
|
||||||
// Good n-gram at the front of the buffer. Publish it, disclosing details.
|
|
||||||
publish(logUnits, true /* canIncludePrivateData */);
|
|
||||||
shiftOutWords(N_GRAM_SIZE);
|
|
||||||
mNumWordsUntilSafeToSample = mNumWordsBetweenNGrams;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// No good n-gram at front, and buffer is full. Shift out up through the first logUnit
|
|
||||||
// with associated words (or if there is none, all the existing logUnits).
|
|
||||||
logUnits.clear();
|
|
||||||
LogUnit logUnit = shiftOut();
|
|
||||||
while (logUnit != null) {
|
|
||||||
logUnits.add(logUnit);
|
|
||||||
final int numWords = logUnit.getNumWords();
|
|
||||||
if (numWords > 0) {
|
|
||||||
mNumWordsUntilSafeToSample = Math.max(0, mNumWordsUntilSafeToSample - numWords);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
logUnit = shiftOut();
|
|
||||||
}
|
|
||||||
publish(logUnits, false /* canIncludePrivateData */);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a list of logUnits should be published.
|
|
||||||
*
|
|
||||||
* It is the subclass's responsibility to implement the publication.
|
|
||||||
*
|
|
||||||
* @param logUnits The list of logUnits to be published.
|
|
||||||
* @param canIncludePrivateData Whether the private data in the logUnits can be included in
|
|
||||||
* publication.
|
|
||||||
*
|
|
||||||
* @throws IOException if publication to the log file is not possible
|
|
||||||
*/
|
|
||||||
protected abstract void publish(final ArrayList<LogUnit> logUnits,
|
|
||||||
final boolean canIncludePrivateData) throws IOException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int shiftOutWords(final int numWords) {
|
|
||||||
final int numWordsShiftedOut = super.shiftOutWords(numWords);
|
|
||||||
mNumWordsUntilSafeToSample = Math.max(0, mNumWordsUntilSafeToSample - numWordsShiftedOut);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "wordsUntilSafeToSample now at " + mNumWordsUntilSafeToSample);
|
|
||||||
}
|
|
||||||
return numWordsShiftedOut;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,324 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.util.JsonReader;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.MotionEvent.PointerCoords;
|
|
||||||
import android.view.MotionEvent.PointerProperties;
|
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class MotionEventReader {
|
|
||||||
private static final String TAG = MotionEventReader.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
// Assumes that MotionEvent.ACTION_MASK does not have all bits set.`
|
|
||||||
private static final int UNINITIALIZED_ACTION = ~MotionEvent.ACTION_MASK;
|
|
||||||
// No legitimate int is negative
|
|
||||||
private static final int UNINITIALIZED_INT = -1;
|
|
||||||
// No legitimate long is negative
|
|
||||||
private static final long UNINITIALIZED_LONG = -1L;
|
|
||||||
// No legitimate float is negative
|
|
||||||
private static final float UNINITIALIZED_FLOAT = -1.0f;
|
|
||||||
|
|
||||||
public ReplayData readMotionEventData(final File file) {
|
|
||||||
final ReplayData replayData = new ReplayData();
|
|
||||||
try {
|
|
||||||
// Read file
|
|
||||||
final JsonReader jsonReader = new JsonReader(new BufferedReader(new InputStreamReader(
|
|
||||||
new FileInputStream(file))));
|
|
||||||
jsonReader.beginArray();
|
|
||||||
while (jsonReader.hasNext()) {
|
|
||||||
readLogStatement(jsonReader, replayData);
|
|
||||||
}
|
|
||||||
jsonReader.endArray();
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return replayData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
static class ReplayData {
|
|
||||||
final ArrayList<Integer> mActions = new ArrayList<>();
|
|
||||||
final ArrayList<PointerProperties[]> mPointerPropertiesArrays = new ArrayList<>();
|
|
||||||
final ArrayList<PointerCoords[]> mPointerCoordsArrays = new ArrayList<>();
|
|
||||||
final ArrayList<Long> mTimes = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read motion data from a logStatement and store it in {@code replayData}.
|
|
||||||
*
|
|
||||||
* Two kinds of logStatements can be read. In the first variant, the MotionEvent data is
|
|
||||||
* represented as attributes at the top level like so:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {
|
|
||||||
* "_ct": 1359590400000,
|
|
||||||
* "_ut": 4381933,
|
|
||||||
* "_ty": "MotionEvent",
|
|
||||||
* "action": "UP",
|
|
||||||
* "isLoggingRelated": false,
|
|
||||||
* "x": 100,
|
|
||||||
* "y": 200
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* In the second variant, there is a separate attribute for the MotionEvent that includes
|
|
||||||
* historical data if present:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {
|
|
||||||
* "_ct": 135959040000,
|
|
||||||
* "_ut": 4382702,
|
|
||||||
* "_ty": "MotionEvent",
|
|
||||||
* "action": "MOVE",
|
|
||||||
* "isLoggingRelated": false,
|
|
||||||
* "motionEvent": {
|
|
||||||
* "pointerIds": [
|
|
||||||
* 0
|
|
||||||
* ],
|
|
||||||
* "xyt": [
|
|
||||||
* {
|
|
||||||
* "t": 4382551,
|
|
||||||
* "d": [
|
|
||||||
* {
|
|
||||||
* "x": 141.25,
|
|
||||||
* "y": 151.8485107421875,
|
|
||||||
* "toma": 101.82337188720703,
|
|
||||||
* "tomi": 101.82337188720703,
|
|
||||||
* "o": 0.0
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* },
|
|
||||||
* {
|
|
||||||
* "t": 4382559,
|
|
||||||
* "d": [
|
|
||||||
* {
|
|
||||||
* "x": 140.7266082763672,
|
|
||||||
* "y": 151.8485107421875,
|
|
||||||
* "toma": 101.82337188720703,
|
|
||||||
* "tomi": 101.82337188720703,
|
|
||||||
* "o": 0.0
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
@UsedForTesting
|
|
||||||
/* package for test */ void readLogStatement(final JsonReader jsonReader,
|
|
||||||
final ReplayData replayData) throws IOException {
|
|
||||||
String logStatementType = null;
|
|
||||||
int actionType = UNINITIALIZED_ACTION;
|
|
||||||
int x = UNINITIALIZED_INT;
|
|
||||||
int y = UNINITIALIZED_INT;
|
|
||||||
long time = UNINITIALIZED_LONG;
|
|
||||||
boolean isLoggingRelated = false;
|
|
||||||
|
|
||||||
jsonReader.beginObject();
|
|
||||||
while (jsonReader.hasNext()) {
|
|
||||||
final String key = jsonReader.nextName();
|
|
||||||
if (key.equals("_ty")) {
|
|
||||||
logStatementType = jsonReader.nextString();
|
|
||||||
} else if (key.equals("_ut")) {
|
|
||||||
time = jsonReader.nextLong();
|
|
||||||
} else if (key.equals("x")) {
|
|
||||||
x = jsonReader.nextInt();
|
|
||||||
} else if (key.equals("y")) {
|
|
||||||
y = jsonReader.nextInt();
|
|
||||||
} else if (key.equals("action")) {
|
|
||||||
final String s = jsonReader.nextString();
|
|
||||||
if (s.equals("UP")) {
|
|
||||||
actionType = MotionEvent.ACTION_UP;
|
|
||||||
} else if (s.equals("DOWN")) {
|
|
||||||
actionType = MotionEvent.ACTION_DOWN;
|
|
||||||
} else if (s.equals("MOVE")) {
|
|
||||||
actionType = MotionEvent.ACTION_MOVE;
|
|
||||||
}
|
|
||||||
} else if (key.equals("loggingRelated")) {
|
|
||||||
isLoggingRelated = jsonReader.nextBoolean();
|
|
||||||
} else if (logStatementType != null && logStatementType.equals("MotionEvent")
|
|
||||||
&& key.equals("motionEvent")) {
|
|
||||||
if (actionType == UNINITIALIZED_ACTION) {
|
|
||||||
Log.e(TAG, "no actionType assigned in MotionEvent json");
|
|
||||||
}
|
|
||||||
// Second variant of LogStatement.
|
|
||||||
if (isLoggingRelated) {
|
|
||||||
jsonReader.skipValue();
|
|
||||||
} else {
|
|
||||||
readEmbeddedMotionEvent(jsonReader, replayData, actionType);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Unknown JSON key in LogStatement: " + key);
|
|
||||||
}
|
|
||||||
jsonReader.skipValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonReader.endObject();
|
|
||||||
|
|
||||||
if (logStatementType != null && time != UNINITIALIZED_LONG && x != UNINITIALIZED_INT
|
|
||||||
&& y != UNINITIALIZED_INT && actionType != UNINITIALIZED_ACTION
|
|
||||||
&& logStatementType.equals("MotionEvent") && !isLoggingRelated) {
|
|
||||||
// First variant of LogStatement.
|
|
||||||
final PointerProperties pointerProperties = new PointerProperties();
|
|
||||||
pointerProperties.id = 0;
|
|
||||||
pointerProperties.toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
|
|
||||||
final PointerProperties[] pointerPropertiesArray = {
|
|
||||||
pointerProperties
|
|
||||||
};
|
|
||||||
final PointerCoords pointerCoords = new PointerCoords();
|
|
||||||
pointerCoords.x = x;
|
|
||||||
pointerCoords.y = y;
|
|
||||||
pointerCoords.pressure = 1.0f;
|
|
||||||
pointerCoords.size = 1.0f;
|
|
||||||
final PointerCoords[] pointerCoordsArray = {
|
|
||||||
pointerCoords
|
|
||||||
};
|
|
||||||
addMotionEventData(replayData, actionType, time, pointerPropertiesArray,
|
|
||||||
pointerCoordsArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readEmbeddedMotionEvent(final JsonReader jsonReader, final ReplayData replayData,
|
|
||||||
final int actionType) throws IOException {
|
|
||||||
jsonReader.beginObject();
|
|
||||||
PointerProperties[] pointerPropertiesArray = null;
|
|
||||||
while (jsonReader.hasNext()) { // pointerIds/xyt
|
|
||||||
final String name = jsonReader.nextName();
|
|
||||||
if (name.equals("pointerIds")) {
|
|
||||||
pointerPropertiesArray = readPointerProperties(jsonReader);
|
|
||||||
} else if (name.equals("xyt")) {
|
|
||||||
readPointerData(jsonReader, replayData, actionType, pointerPropertiesArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonReader.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PointerProperties[] readPointerProperties(final JsonReader jsonReader)
|
|
||||||
throws IOException {
|
|
||||||
final ArrayList<PointerProperties> pointerPropertiesArrayList = new ArrayList<>();
|
|
||||||
jsonReader.beginArray();
|
|
||||||
while (jsonReader.hasNext()) {
|
|
||||||
final PointerProperties pointerProperties = new PointerProperties();
|
|
||||||
pointerProperties.id = jsonReader.nextInt();
|
|
||||||
pointerProperties.toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
|
|
||||||
pointerPropertiesArrayList.add(pointerProperties);
|
|
||||||
}
|
|
||||||
jsonReader.endArray();
|
|
||||||
return pointerPropertiesArrayList.toArray(
|
|
||||||
new PointerProperties[pointerPropertiesArrayList.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readPointerData(final JsonReader jsonReader, final ReplayData replayData,
|
|
||||||
final int actionType, final PointerProperties[] pointerPropertiesArray)
|
|
||||||
throws IOException {
|
|
||||||
if (pointerPropertiesArray == null) {
|
|
||||||
Log.e(TAG, "PointerIDs must be given before xyt data in json for MotionEvent");
|
|
||||||
jsonReader.skipValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long time = UNINITIALIZED_LONG;
|
|
||||||
jsonReader.beginArray();
|
|
||||||
while (jsonReader.hasNext()) { // Array of historical data
|
|
||||||
jsonReader.beginObject();
|
|
||||||
final ArrayList<PointerCoords> pointerCoordsArrayList = new ArrayList<>();
|
|
||||||
while (jsonReader.hasNext()) { // Time/data object
|
|
||||||
final String name = jsonReader.nextName();
|
|
||||||
if (name.equals("t")) {
|
|
||||||
time = jsonReader.nextLong();
|
|
||||||
} else if (name.equals("d")) {
|
|
||||||
jsonReader.beginArray();
|
|
||||||
while (jsonReader.hasNext()) { // array of data per pointer
|
|
||||||
final PointerCoords pointerCoords = readPointerCoords(jsonReader);
|
|
||||||
if (pointerCoords != null) {
|
|
||||||
pointerCoordsArrayList.add(pointerCoords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonReader.endArray();
|
|
||||||
} else {
|
|
||||||
jsonReader.skipValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonReader.endObject();
|
|
||||||
// Data was recorded as historical events, but must be split apart into
|
|
||||||
// separate MotionEvents for replaying
|
|
||||||
if (time != UNINITIALIZED_LONG) {
|
|
||||||
addMotionEventData(replayData, actionType, time, pointerPropertiesArray,
|
|
||||||
pointerCoordsArrayList.toArray(
|
|
||||||
new PointerCoords[pointerCoordsArrayList.size()]));
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Time not assigned in json for MotionEvent");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonReader.endArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PointerCoords readPointerCoords(final JsonReader jsonReader) throws IOException {
|
|
||||||
jsonReader.beginObject();
|
|
||||||
float x = UNINITIALIZED_FLOAT;
|
|
||||||
float y = UNINITIALIZED_FLOAT;
|
|
||||||
while (jsonReader.hasNext()) { // x,y
|
|
||||||
final String name = jsonReader.nextName();
|
|
||||||
if (name.equals("x")) {
|
|
||||||
x = (float) jsonReader.nextDouble();
|
|
||||||
} else if (name.equals("y")) {
|
|
||||||
y = (float) jsonReader.nextDouble();
|
|
||||||
} else {
|
|
||||||
jsonReader.skipValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsonReader.endObject();
|
|
||||||
|
|
||||||
if (Float.compare(x, UNINITIALIZED_FLOAT) == 0
|
|
||||||
|| Float.compare(y, UNINITIALIZED_FLOAT) == 0) {
|
|
||||||
Log.w(TAG, "missing x or y value in MotionEvent json");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final PointerCoords pointerCoords = new PointerCoords();
|
|
||||||
pointerCoords.x = x;
|
|
||||||
pointerCoords.y = y;
|
|
||||||
pointerCoords.pressure = 1.0f;
|
|
||||||
pointerCoords.size = 1.0f;
|
|
||||||
return pointerCoords;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMotionEventData(final ReplayData replayData, final int actionType,
|
|
||||||
final long time, final PointerProperties[] pointerProperties,
|
|
||||||
final PointerCoords[] pointerCoords) {
|
|
||||||
replayData.mActions.add(actionType);
|
|
||||||
replayData.mTimes.add(time);
|
|
||||||
replayData.mPointerPropertiesArrays.add(pointerProperties);
|
|
||||||
replayData.mPointerCoordsArrays.add(pointerCoords);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.MotionEvent.PointerCoords;
|
|
||||||
import android.view.MotionEvent.PointerProperties;
|
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
|
||||||
import com.android.inputmethod.keyboard.MainKeyboardView;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
import com.android.inputmethod.research.MotionEventReader.ReplayData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replays a sequence of motion events in realtime on the screen.
|
|
||||||
*
|
|
||||||
* Useful for user inspection of logged data.
|
|
||||||
*/
|
|
||||||
public class Replayer {
|
|
||||||
private static final String TAG = Replayer.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
private static final long START_TIME_DELAY_MS = 500;
|
|
||||||
|
|
||||||
private boolean mIsReplaying = false;
|
|
||||||
private KeyboardSwitcher mKeyboardSwitcher;
|
|
||||||
|
|
||||||
private Replayer() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Replayer sInstance = new Replayer();
|
|
||||||
public static Replayer getInstance() {
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeyboardSwitcher(final KeyboardSwitcher keyboardSwitcher) {
|
|
||||||
mKeyboardSwitcher = keyboardSwitcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int MSG_MOTION_EVENT = 0;
|
|
||||||
private static final int MSG_DONE = 1;
|
|
||||||
private static final int COMPLETION_TIME_MS = 500;
|
|
||||||
|
|
||||||
// TODO: Support historical events and multi-touch.
|
|
||||||
public void replay(final ReplayData replayData, final Runnable callback) {
|
|
||||||
if (mIsReplaying) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mIsReplaying = true;
|
|
||||||
final int numActions = replayData.mActions.size();
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "replaying " + numActions + " actions");
|
|
||||||
}
|
|
||||||
if (numActions == 0) {
|
|
||||||
mIsReplaying = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
|
|
||||||
|
|
||||||
// The reference time relative to the times stored in events.
|
|
||||||
final long origStartTime = replayData.mTimes.get(0);
|
|
||||||
// The reference time relative to which events are replayed in the present.
|
|
||||||
final long currentStartTime = SystemClock.uptimeMillis() + START_TIME_DELAY_MS;
|
|
||||||
// The adjustment needed to translate times from the original recorded time to the current
|
|
||||||
// time.
|
|
||||||
final long timeAdjustment = currentStartTime - origStartTime;
|
|
||||||
final Handler handler = new Handler(Looper.getMainLooper()) {
|
|
||||||
// Track the time of the most recent DOWN event, to be passed as a parameter when
|
|
||||||
// constructing a MotionEvent. It's initialized here to the origStartTime, but this is
|
|
||||||
// only a precaution. The value should be overwritten by the first ACTION_DOWN event
|
|
||||||
// before the first use of the variable. Note that this may cause the first few events
|
|
||||||
// to have incorrect {@code downTime}s.
|
|
||||||
private long mOrigDownTime = origStartTime;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(final Message msg) {
|
|
||||||
switch (msg.what) {
|
|
||||||
case MSG_MOTION_EVENT:
|
|
||||||
final int index = msg.arg1;
|
|
||||||
final int action = replayData.mActions.get(index);
|
|
||||||
final PointerProperties[] pointerPropertiesArray =
|
|
||||||
replayData.mPointerPropertiesArrays.get(index);
|
|
||||||
final PointerCoords[] pointerCoordsArray =
|
|
||||||
replayData.mPointerCoordsArrays.get(index);
|
|
||||||
final long origTime = replayData.mTimes.get(index);
|
|
||||||
if (action == MotionEvent.ACTION_DOWN) {
|
|
||||||
mOrigDownTime = origTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
final MotionEvent me = MotionEvent.obtain(mOrigDownTime + timeAdjustment,
|
|
||||||
origTime + timeAdjustment, action,
|
|
||||||
pointerPropertiesArray.length, pointerPropertiesArray,
|
|
||||||
pointerCoordsArray, 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
|
|
||||||
mainKeyboardView.processMotionEvent(me);
|
|
||||||
me.recycle();
|
|
||||||
break;
|
|
||||||
case MSG_DONE:
|
|
||||||
mIsReplaying = false;
|
|
||||||
ResearchLogger.getInstance().requestIndicatorRedraw();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
ResearchLogger.getInstance().requestIndicatorRedraw();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (int i = 0; i < numActions; i++) {
|
|
||||||
final Message msg = Message.obtain(handler, MSG_MOTION_EVENT, i, 0);
|
|
||||||
final long msgTime = replayData.mTimes.get(i) + timeAdjustment;
|
|
||||||
handler.sendMessageAtTime(msg, msgTime);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "queuing event at " + msgTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final long presentDoneTime = replayData.mTimes.get(numActions - 1) + timeAdjustment
|
|
||||||
+ COMPLETION_TIME_MS;
|
|
||||||
handler.sendMessageAtTime(Message.obtain(handler, MSG_DONE), presentDoneTime);
|
|
||||||
if (callback != null) {
|
|
||||||
handler.postAtTime(callback, presentDoneTime + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReplaying() {
|
|
||||||
return mIsReplaying;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.app.IntentService;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.android.inputmethod.research.MotionEventReader.ReplayData;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide a mechanism to invoke the replayer from outside.
|
|
||||||
*
|
|
||||||
* In particular, makes access from a host possible through {@code adb am startservice}.
|
|
||||||
*/
|
|
||||||
public class ReplayerService extends IntentService {
|
|
||||||
private static final String TAG = ReplayerService.class.getSimpleName();
|
|
||||||
private static final String EXTRA_FILENAME = "com.android.inputmethod.research.extra.FILENAME";
|
|
||||||
private static final long MAX_REPLAY_TIME = TimeUnit.SECONDS.toMillis(60);
|
|
||||||
|
|
||||||
public ReplayerService() {
|
|
||||||
super(ReplayerService.class.getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHandleIntent(final Intent intent) {
|
|
||||||
final String filename = intent.getStringExtra(EXTRA_FILENAME);
|
|
||||||
if (filename == null) return;
|
|
||||||
|
|
||||||
final ReplayData replayData = new MotionEventReader().readMotionEventData(
|
|
||||||
new File(filename));
|
|
||||||
synchronized (this) {
|
|
||||||
Replayer.getInstance().replay(replayData, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
synchronized (ReplayerService.this) {
|
|
||||||
ReplayerService.this.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
wait(MAX_REPLAY_TIME);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(TAG, "Timeout while replaying.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,298 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.JsonWriter;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the use of the LatinIME keyboard.
|
|
||||||
*
|
|
||||||
* This class logs operations on the IME keyboard, including what the user has typed. Data is
|
|
||||||
* written to a {@link JsonWriter}, which will write to a local file.
|
|
||||||
*
|
|
||||||
* The JsonWriter is created on-demand by calling {@link #getInitializedJsonWriterLocked}.
|
|
||||||
*
|
|
||||||
* This class uses an executor to perform file-writing operations on a separate thread. It also
|
|
||||||
* tries to avoid creating unnecessary files if there is nothing to write. It also handles
|
|
||||||
* flushing, making sure it happens, but not too frequently.
|
|
||||||
*
|
|
||||||
* This functionality is off by default. See
|
|
||||||
* {@link ProductionFlag#USES_DEVELOPMENT_ONLY_DIAGNOSTICS}.
|
|
||||||
*/
|
|
||||||
public class ResearchLog {
|
|
||||||
// TODO: Automatically initialize the JsonWriter rather than requiring the caller to manage it.
|
|
||||||
private static final String TAG = ResearchLog.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
private static final long FLUSH_DELAY_IN_MS = TimeUnit.SECONDS.toMillis(5);
|
|
||||||
|
|
||||||
/* package */ final ScheduledExecutorService mExecutor;
|
|
||||||
/* package */ final File mFile;
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
// Earlier implementations used a dummy JsonWriter that just swallowed what it was given, but
|
|
||||||
// this was tricky to do well, because JsonWriter throws an exception if it is passed more than
|
|
||||||
// one top-level object.
|
|
||||||
private JsonWriter mJsonWriter = null;
|
|
||||||
|
|
||||||
// true if at least one byte of data has been written out to the log file. This must be
|
|
||||||
// remembered because JsonWriter requires that calls matching calls to beginObject and
|
|
||||||
// endObject, as well as beginArray and endArray, and the file is opened lazily, only when
|
|
||||||
// it is certain that data will be written. Alternatively, the matching call exceptions
|
|
||||||
// could be caught, but this might suppress other errors.
|
|
||||||
private boolean mHasWrittenData = false;
|
|
||||||
|
|
||||||
public ResearchLog(final File outputFile, final Context context) {
|
|
||||||
mExecutor = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
mFile = outputFile;
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this is a FeedbackLog.
|
|
||||||
*
|
|
||||||
* FeedbackLogs record only the data associated with a Feedback dialog. Instead of normal
|
|
||||||
* logging, they contain a LogStatement with the complete feedback string and optionally a
|
|
||||||
* recording of the user's supplied demo of the problem.
|
|
||||||
*/
|
|
||||||
public boolean isFeedbackLog() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits for any publication requests to finish and closes the {@link JsonWriter} used for
|
|
||||||
* output.
|
|
||||||
*
|
|
||||||
* See class comment for details about {@code JsonWriter} construction.
|
|
||||||
*
|
|
||||||
* @param onClosed run after the close() operation has completed asynchronously
|
|
||||||
*/
|
|
||||||
private synchronized void close(final Runnable onClosed) {
|
|
||||||
mExecutor.submit(new Callable<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
|
||||||
try {
|
|
||||||
if (mJsonWriter == null) return null;
|
|
||||||
// TODO: This is necessary to avoid an exception. Better would be to not even
|
|
||||||
// open the JsonWriter if the file is not even opened unless there is valid data
|
|
||||||
// to write.
|
|
||||||
if (!mHasWrittenData) {
|
|
||||||
mJsonWriter.beginArray();
|
|
||||||
}
|
|
||||||
mJsonWriter.endArray();
|
|
||||||
mHasWrittenData = false;
|
|
||||||
mJsonWriter.flush();
|
|
||||||
mJsonWriter.close();
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "closed " + mFile);
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
Log.d(TAG, "error when closing ResearchLog:", e);
|
|
||||||
} finally {
|
|
||||||
// Marking the file as read-only signals that this log file is ready to be
|
|
||||||
// uploaded.
|
|
||||||
if (mFile != null && mFile.exists()) {
|
|
||||||
mFile.setWritable(false, false);
|
|
||||||
}
|
|
||||||
if (onClosed != null) {
|
|
||||||
onClosed.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
removeAnyScheduledFlush();
|
|
||||||
mExecutor.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block until the research log has shut down and spooled out all output or {@code timeout}
|
|
||||||
* occurs.
|
|
||||||
*
|
|
||||||
* @param timeout time to wait for close in milliseconds
|
|
||||||
*/
|
|
||||||
public void blockingClose(final long timeout) {
|
|
||||||
close(null);
|
|
||||||
awaitTermination(timeout, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits for publication requests to finish, closes the JsonWriter, but then deletes the backing
|
|
||||||
* output file.
|
|
||||||
*
|
|
||||||
* @param onAbort run after the abort() operation has completed asynchronously
|
|
||||||
*/
|
|
||||||
private synchronized void abort(final Runnable onAbort) {
|
|
||||||
mExecutor.submit(new Callable<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
|
||||||
try {
|
|
||||||
if (mJsonWriter == null) return null;
|
|
||||||
if (mHasWrittenData) {
|
|
||||||
// TODO: This is necessary to avoid an exception. Better would be to not
|
|
||||||
// even open the JsonWriter if the file is not even opened unless there is
|
|
||||||
// valid data to write.
|
|
||||||
if (!mHasWrittenData) {
|
|
||||||
mJsonWriter.beginArray();
|
|
||||||
}
|
|
||||||
mJsonWriter.endArray();
|
|
||||||
mJsonWriter.close();
|
|
||||||
mHasWrittenData = false;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (mFile != null) {
|
|
||||||
mFile.delete();
|
|
||||||
}
|
|
||||||
if (onAbort != null) {
|
|
||||||
onAbort.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
removeAnyScheduledFlush();
|
|
||||||
mExecutor.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block until the research log has aborted or {@code timeout} occurs.
|
|
||||||
*
|
|
||||||
* @param timeout time to wait for close in milliseconds
|
|
||||||
*/
|
|
||||||
public void blockingAbort(final long timeout) {
|
|
||||||
abort(null);
|
|
||||||
awaitTermination(timeout, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
public void awaitTermination(final long delay, final TimeUnit timeUnit) {
|
|
||||||
try {
|
|
||||||
if (!mExecutor.awaitTermination(delay, timeUnit)) {
|
|
||||||
Log.e(TAG, "ResearchLog executor timed out while awaiting terminaion");
|
|
||||||
}
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
Log.e(TAG, "ResearchLog executor interrupted while awaiting terminaion", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ synchronized void flush() {
|
|
||||||
removeAnyScheduledFlush();
|
|
||||||
mExecutor.submit(mFlushCallable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Callable<Object> mFlushCallable = new Callable<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
|
||||||
if (mJsonWriter != null) mJsonWriter.flush();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private ScheduledFuture<Object> mFlushFuture;
|
|
||||||
|
|
||||||
private void removeAnyScheduledFlush() {
|
|
||||||
if (mFlushFuture != null) {
|
|
||||||
mFlushFuture.cancel(false);
|
|
||||||
mFlushFuture = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scheduleFlush() {
|
|
||||||
removeAnyScheduledFlush();
|
|
||||||
mFlushFuture = mExecutor.schedule(mFlushCallable, FLUSH_DELAY_IN_MS, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues up {@code logUnit} to be published in the background.
|
|
||||||
*
|
|
||||||
* @param logUnit the {@link LogUnit} to be published
|
|
||||||
* @param canIncludePrivateData whether private data in the LogUnit should be included
|
|
||||||
*/
|
|
||||||
public synchronized void publish(final LogUnit logUnit, final boolean canIncludePrivateData) {
|
|
||||||
try {
|
|
||||||
mExecutor.submit(new Callable<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object call() throws Exception {
|
|
||||||
logUnit.publishTo(ResearchLog.this, canIncludePrivateData);
|
|
||||||
scheduleFlush();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (final RejectedExecutionException e) {
|
|
||||||
// TODO: Add code to record loss of data, and report.
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "ResearchLog.publish() rejecting scheduled execution", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a JsonWriter for this ResearchLog. It is initialized the first time this method is
|
|
||||||
* called. The cached value is returned in future calls.
|
|
||||||
*
|
|
||||||
* @throws IOException if opening the JsonWriter is not possible
|
|
||||||
*/
|
|
||||||
public JsonWriter getInitializedJsonWriterLocked() throws IOException {
|
|
||||||
if (mJsonWriter != null) return mJsonWriter;
|
|
||||||
if (mFile == null) throw new FileNotFoundException();
|
|
||||||
try {
|
|
||||||
final JsonWriter jsonWriter = createJsonWriter(mContext, mFile);
|
|
||||||
if (jsonWriter == null) throw new IOException("Could not create JsonWriter");
|
|
||||||
|
|
||||||
jsonWriter.beginArray();
|
|
||||||
mJsonWriter = jsonWriter;
|
|
||||||
mHasWrittenData = true;
|
|
||||||
return mJsonWriter;
|
|
||||||
} catch (final IOException e) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Exception when creating JsonWriter", e);
|
|
||||||
Log.w(TAG, "Closing JsonWriter");
|
|
||||||
}
|
|
||||||
if (mJsonWriter != null) mJsonWriter.close();
|
|
||||||
mJsonWriter = null;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the JsonWriter to write the ResearchLog to.
|
|
||||||
*
|
|
||||||
* This method may be overriden in testing to redirect the output.
|
|
||||||
*/
|
|
||||||
/* package for test */ JsonWriter createJsonWriter(final Context context, final File file)
|
|
||||||
throws IOException {
|
|
||||||
return new JsonWriter(new BufferedWriter(new OutputStreamWriter(
|
|
||||||
context.openFileOutput(file.getName(), Context.MODE_PRIVATE))));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages log files.
|
|
||||||
*
|
|
||||||
* This class handles all aspects where and how research log data is stored. This includes
|
|
||||||
* generating log filenames in the correct place with the correct names, and cleaning up log files
|
|
||||||
* under this directory.
|
|
||||||
*/
|
|
||||||
public class ResearchLogDirectory {
|
|
||||||
public static final String TAG = ResearchLogDirectory.class.getSimpleName();
|
|
||||||
/* package */ static final String LOG_FILENAME_PREFIX = "researchLog";
|
|
||||||
private static final String FILENAME_SUFFIX = ".txt";
|
|
||||||
private static final String USER_RECORDING_FILENAME_PREFIX = "recording";
|
|
||||||
|
|
||||||
private static final ReadOnlyLogFileFilter sUploadableLogFileFilter =
|
|
||||||
new ReadOnlyLogFileFilter();
|
|
||||||
|
|
||||||
private final File mFilesDir;
|
|
||||||
|
|
||||||
static class ReadOnlyLogFileFilter implements FileFilter {
|
|
||||||
@Override
|
|
||||||
public boolean accept(final File pathname) {
|
|
||||||
return pathname.getName().startsWith(ResearchLogDirectory.LOG_FILENAME_PREFIX)
|
|
||||||
&& !pathname.canWrite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ResearchLogDirectory, creating the storage directory if it does not exist.
|
|
||||||
*/
|
|
||||||
public ResearchLogDirectory(final Context context) {
|
|
||||||
mFilesDir = getLoggingDirectory(context);
|
|
||||||
if (mFilesDir == null) {
|
|
||||||
throw new NullPointerException("No files directory specified");
|
|
||||||
}
|
|
||||||
if (!mFilesDir.exists()) {
|
|
||||||
mFilesDir.mkdirs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getLoggingDirectory(final Context context) {
|
|
||||||
// TODO: Switch to using a subdirectory of getFilesDir().
|
|
||||||
return context.getFilesDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an array of log files that are ready for uploading.
|
|
||||||
*
|
|
||||||
* A file is ready for uploading if it is marked as read-only.
|
|
||||||
*
|
|
||||||
* @return the array of uploadable files
|
|
||||||
*/
|
|
||||||
public File[] getUploadableLogFiles() {
|
|
||||||
try {
|
|
||||||
return mFilesDir.listFiles(sUploadableLogFileFilter);
|
|
||||||
} catch (final SecurityException e) {
|
|
||||||
Log.e(TAG, "Could not cleanup log directory, permission denied", e);
|
|
||||||
return new File[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanupLogFilesOlderThan(final long time) {
|
|
||||||
try {
|
|
||||||
for (final File file : mFilesDir.listFiles()) {
|
|
||||||
final String filename = file.getName();
|
|
||||||
if ((filename.startsWith(LOG_FILENAME_PREFIX)
|
|
||||||
|| filename.startsWith(USER_RECORDING_FILENAME_PREFIX))
|
|
||||||
&& (file.lastModified() < time)) {
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final SecurityException e) {
|
|
||||||
Log.e(TAG, "Could not cleanup log directory, permission denied", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getLogFilePath(final long time, final long nanoTime) {
|
|
||||||
return new File(mFilesDir, getUniqueFilename(LOG_FILENAME_PREFIX, time, nanoTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getUserRecordingFilePath(final long time, final long nanoTime) {
|
|
||||||
return new File(mFilesDir, getUniqueFilename(USER_RECORDING_FILENAME_PREFIX, time,
|
|
||||||
nanoTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getUniqueFilename(final String prefix, final long time,
|
|
||||||
final long nanoTime) {
|
|
||||||
return prefix + "-" + time + "-" + nanoTime + FILENAME_SUFFIX;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public final class ResearchSettings {
|
|
||||||
public static final String PREF_RESEARCH_LOGGER_UUID = "pref_research_logger_uuid";
|
|
||||||
public static final String PREF_RESEARCH_LOGGER_ENABLED_FLAG =
|
|
||||||
"pref_research_logger_enabled_flag";
|
|
||||||
public static final String PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH =
|
|
||||||
"pref_research_logger_has_seen_splash";
|
|
||||||
public static final String PREF_RESEARCH_LAST_DIR_CLEANUP_TIME =
|
|
||||||
"pref_research_last_dir_cleanup_time";
|
|
||||||
|
|
||||||
private ResearchSettings() {
|
|
||||||
// Intentional empty constructor for singleton.
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String readResearchLoggerUuid(final SharedPreferences prefs) {
|
|
||||||
if (prefs.contains(PREF_RESEARCH_LOGGER_UUID)) {
|
|
||||||
return prefs.getString(PREF_RESEARCH_LOGGER_UUID, null);
|
|
||||||
}
|
|
||||||
// Generate a random string as uuid if not yet set
|
|
||||||
final String newUuid = UUID.randomUUID().toString();
|
|
||||||
prefs.edit().putString(PREF_RESEARCH_LOGGER_UUID, newUuid).apply();
|
|
||||||
return newUuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean readResearchLoggerEnabledFlag(final SharedPreferences prefs) {
|
|
||||||
return prefs.getBoolean(PREF_RESEARCH_LOGGER_ENABLED_FLAG, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeResearchLoggerEnabledFlag(final SharedPreferences prefs,
|
|
||||||
final boolean isEnabled) {
|
|
||||||
prefs.edit().putBoolean(PREF_RESEARCH_LOGGER_ENABLED_FLAG, isEnabled).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean readHasSeenSplash(final SharedPreferences prefs) {
|
|
||||||
return prefs.getBoolean(PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeHasSeenSplash(final SharedPreferences prefs,
|
|
||||||
final boolean hasSeenSplash) {
|
|
||||||
prefs.edit().putBoolean(PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH, hasSeenSplash).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long readResearchLastDirCleanupTime(final SharedPreferences prefs) {
|
|
||||||
return prefs.getLong(PREF_RESEARCH_LAST_DIR_CLEANUP_TIME, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeResearchLastDirCleanupTime(final SharedPreferences prefs,
|
|
||||||
final long lastDirCleanupTime) {
|
|
||||||
prefs.edit().putLong(PREF_RESEARCH_LAST_DIR_CLEANUP_TIME, lastDirCleanupTime).apply();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,279 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.Constants;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class Statistics {
|
|
||||||
private static final String TAG = Statistics.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = false
|
|
||||||
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
|
||||||
|
|
||||||
// TODO: Cleanup comments to only including those giving meaningful information.
|
|
||||||
// Number of characters entered during a typing session
|
|
||||||
int mCharCount;
|
|
||||||
// Number of letter characters entered during a typing session
|
|
||||||
int mLetterCount;
|
|
||||||
// Number of number characters entered
|
|
||||||
int mNumberCount;
|
|
||||||
// Number of space characters entered
|
|
||||||
int mSpaceCount;
|
|
||||||
// Number of delete operations entered (taps on the backspace key)
|
|
||||||
int mDeleteKeyCount;
|
|
||||||
// Number of words entered during a session.
|
|
||||||
int mWordCount;
|
|
||||||
// Number of words found in the dictionary.
|
|
||||||
int mDictionaryWordCount;
|
|
||||||
// Number of words split and spaces automatically entered.
|
|
||||||
int mSplitWordsCount;
|
|
||||||
// Number of words entered during a session.
|
|
||||||
int mCorrectedWordsCount;
|
|
||||||
// Number of gestures that were input.
|
|
||||||
int mGesturesInputCount;
|
|
||||||
// Number of gestures that were deleted.
|
|
||||||
int mGesturesDeletedCount;
|
|
||||||
// Total number of characters in words entered by gesture.
|
|
||||||
int mGesturesCharsCount;
|
|
||||||
// Number of manual suggestions chosen.
|
|
||||||
int mManualSuggestionsCount;
|
|
||||||
// Number of times that autocorrection was invoked.
|
|
||||||
int mAutoCorrectionsCount;
|
|
||||||
// Number of times a commit was reverted in this session.
|
|
||||||
int mRevertCommitsCount;
|
|
||||||
// Whether the text field was empty upon editing
|
|
||||||
boolean mIsEmptyUponStarting;
|
|
||||||
boolean mIsEmptinessStateKnown;
|
|
||||||
|
|
||||||
// Counts of how often an n-gram is collected or not, and the reasons for the decision.
|
|
||||||
// Keep consistent with publishability result code list in MainLogBuffer
|
|
||||||
int mPublishableCount;
|
|
||||||
int mUnpublishableStoppingCount;
|
|
||||||
int mUnpublishableIncorrectWordCount;
|
|
||||||
int mUnpublishableSampledTooRecently;
|
|
||||||
int mUnpublishableDictionaryUnavailable;
|
|
||||||
int mUnpublishableMayContainDigit;
|
|
||||||
int mUnpublishableNotInDictionary;
|
|
||||||
|
|
||||||
// Timers to count average time to enter a key, first press a delete key,
|
|
||||||
// between delete keys, and then to return typing after a delete key.
|
|
||||||
final AverageTimeCounter mKeyCounter = new AverageTimeCounter();
|
|
||||||
final AverageTimeCounter mBeforeDeleteKeyCounter = new AverageTimeCounter();
|
|
||||||
final AverageTimeCounter mDuringRepeatedDeleteKeysCounter = new AverageTimeCounter();
|
|
||||||
final AverageTimeCounter mAfterDeleteKeyCounter = new AverageTimeCounter();
|
|
||||||
|
|
||||||
static class AverageTimeCounter {
|
|
||||||
int mCount;
|
|
||||||
int mTotalTime;
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
mCount = 0;
|
|
||||||
mTotalTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(long deltaTime) {
|
|
||||||
mCount++;
|
|
||||||
mTotalTime += deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAverageTime() {
|
|
||||||
if (mCount == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mTotalTime / mCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To account for the interruptions when the user's attention is directed elsewhere, times
|
|
||||||
// longer than MIN_TYPING_INTERMISSION are not counted when estimating this statistic.
|
|
||||||
public static final long MIN_TYPING_INTERMISSION = TimeUnit.SECONDS.toMillis(2);
|
|
||||||
public static final long MIN_DELETION_INTERMISSION = TimeUnit.SECONDS.toMillis(10);
|
|
||||||
|
|
||||||
// The last time that a tap was performed
|
|
||||||
private long mLastTapTime;
|
|
||||||
// The type of the last keypress (delete key or not)
|
|
||||||
boolean mIsLastKeyDeleteKey;
|
|
||||||
|
|
||||||
private static final Statistics sInstance = new Statistics();
|
|
||||||
|
|
||||||
public static Statistics getInstance() {
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Statistics() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
mCharCount = 0;
|
|
||||||
mLetterCount = 0;
|
|
||||||
mNumberCount = 0;
|
|
||||||
mSpaceCount = 0;
|
|
||||||
mDeleteKeyCount = 0;
|
|
||||||
mWordCount = 0;
|
|
||||||
mDictionaryWordCount = 0;
|
|
||||||
mSplitWordsCount = 0;
|
|
||||||
mCorrectedWordsCount = 0;
|
|
||||||
mGesturesInputCount = 0;
|
|
||||||
mGesturesDeletedCount = 0;
|
|
||||||
mManualSuggestionsCount = 0;
|
|
||||||
mRevertCommitsCount = 0;
|
|
||||||
mAutoCorrectionsCount = 0;
|
|
||||||
mIsEmptyUponStarting = true;
|
|
||||||
mIsEmptinessStateKnown = false;
|
|
||||||
mKeyCounter.reset();
|
|
||||||
mBeforeDeleteKeyCounter.reset();
|
|
||||||
mDuringRepeatedDeleteKeysCounter.reset();
|
|
||||||
mAfterDeleteKeyCounter.reset();
|
|
||||||
mGesturesCharsCount = 0;
|
|
||||||
mGesturesDeletedCount = 0;
|
|
||||||
mPublishableCount = 0;
|
|
||||||
mUnpublishableStoppingCount = 0;
|
|
||||||
mUnpublishableIncorrectWordCount = 0;
|
|
||||||
mUnpublishableSampledTooRecently = 0;
|
|
||||||
mUnpublishableDictionaryUnavailable = 0;
|
|
||||||
mUnpublishableMayContainDigit = 0;
|
|
||||||
mUnpublishableNotInDictionary = 0;
|
|
||||||
|
|
||||||
mLastTapTime = 0;
|
|
||||||
mIsLastKeyDeleteKey = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordChar(int codePoint, long time) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "recordChar() called");
|
|
||||||
}
|
|
||||||
if (codePoint == Constants.CODE_DELETE) {
|
|
||||||
mDeleteKeyCount++;
|
|
||||||
recordUserAction(time, true /* isDeletion */);
|
|
||||||
} else {
|
|
||||||
mCharCount++;
|
|
||||||
if (Character.isDigit(codePoint)) {
|
|
||||||
mNumberCount++;
|
|
||||||
}
|
|
||||||
if (Character.isLetter(codePoint)) {
|
|
||||||
mLetterCount++;
|
|
||||||
}
|
|
||||||
if (Character.isSpaceChar(codePoint)) {
|
|
||||||
mSpaceCount++;
|
|
||||||
}
|
|
||||||
recordUserAction(time, false /* isDeletion */);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordWordEntered(final boolean isDictionaryWord,
|
|
||||||
final boolean containsCorrection) {
|
|
||||||
mWordCount++;
|
|
||||||
if (isDictionaryWord) {
|
|
||||||
mDictionaryWordCount++;
|
|
||||||
}
|
|
||||||
if (containsCorrection) {
|
|
||||||
mCorrectedWordsCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordSplitWords() {
|
|
||||||
mSplitWordsCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordGestureInput(final int numCharsEntered, final long time) {
|
|
||||||
mGesturesInputCount++;
|
|
||||||
mGesturesCharsCount += numCharsEntered;
|
|
||||||
recordUserAction(time, false /* isDeletion */);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsEmptyUponStarting(final boolean isEmpty) {
|
|
||||||
mIsEmptyUponStarting = isEmpty;
|
|
||||||
mIsEmptinessStateKnown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordGestureDelete(final int length, final long time) {
|
|
||||||
mGesturesDeletedCount++;
|
|
||||||
recordUserAction(time, true /* isDeletion */);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordManualSuggestion(final long time) {
|
|
||||||
mManualSuggestionsCount++;
|
|
||||||
recordUserAction(time, false /* isDeletion */);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordAutoCorrection(final long time) {
|
|
||||||
mAutoCorrectionsCount++;
|
|
||||||
recordUserAction(time, false /* isDeletion */);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordRevertCommit(final long time) {
|
|
||||||
mRevertCommitsCount++;
|
|
||||||
recordUserAction(time, true /* isDeletion */);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void recordUserAction(final long time, final boolean isDeletion) {
|
|
||||||
final long delta = time - mLastTapTime;
|
|
||||||
if (isDeletion) {
|
|
||||||
if (delta < MIN_DELETION_INTERMISSION) {
|
|
||||||
if (mIsLastKeyDeleteKey) {
|
|
||||||
mDuringRepeatedDeleteKeysCounter.add(delta);
|
|
||||||
} else {
|
|
||||||
mBeforeDeleteKeyCounter.add(delta);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ResearchLogger.onUserPause(delta);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mIsLastKeyDeleteKey && delta < MIN_DELETION_INTERMISSION) {
|
|
||||||
mAfterDeleteKeyCounter.add(delta);
|
|
||||||
} else if (!mIsLastKeyDeleteKey && delta < MIN_TYPING_INTERMISSION) {
|
|
||||||
mKeyCounter.add(delta);
|
|
||||||
} else {
|
|
||||||
ResearchLogger.onUserPause(delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mIsLastKeyDeleteKey = isDeletion;
|
|
||||||
mLastTapTime = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordPublishabilityResultCode(final int publishabilityResultCode) {
|
|
||||||
// Keep consistent with publishability result code list in MainLogBuffer
|
|
||||||
switch (publishabilityResultCode) {
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_PUBLISHABLE:
|
|
||||||
mPublishableCount++;
|
|
||||||
break;
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_STOPPING:
|
|
||||||
mUnpublishableStoppingCount++;
|
|
||||||
break;
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_INCORRECT_WORD_COUNT:
|
|
||||||
mUnpublishableIncorrectWordCount++;
|
|
||||||
break;
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_SAMPLED_TOO_RECENTLY:
|
|
||||||
mUnpublishableSampledTooRecently++;
|
|
||||||
break;
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_DICTIONARY_UNAVAILABLE:
|
|
||||||
mUnpublishableDictionaryUnavailable++;
|
|
||||||
break;
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_MAY_CONTAIN_DIGIT:
|
|
||||||
mUnpublishableMayContainDigit++;
|
|
||||||
break;
|
|
||||||
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_NOT_IN_DICTIONARY:
|
|
||||||
mUnpublishableNotInDictionary++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue