diff options
Diffstat (limited to 'java/src/com/android/inputmethod')
5 files changed, 311 insertions, 46 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 8953cb8d1..4248921f4 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -20,6 +20,7 @@ import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII; import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE; import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT; +import android.app.Activity; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -38,7 +39,6 @@ import android.os.Debug; import android.os.IBinder; import android.os.Message; import android.os.SystemClock; -import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.text.InputType; import android.text.TextUtils; @@ -2111,18 +2111,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen }; private void launchSettings() { - launchSettingsClass(SettingsActivity.class); + handleClose(); + launchSubActivity(SettingsActivity.class); } // Called from debug code only public void launchDebugSettings() { - launchSettingsClass(DebugSettingsActivity.class); + handleClose(); + launchSubActivity(DebugSettingsActivity.class); } - private void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) { - handleClose(); + public void launchKeyboardedDialogActivity(Class<? extends Activity> activityClass) { + // Put the text in the attached EditText into a safe, saved state before switching to a + // new activity that will also use the soft keyboard. + commitTyped(LastComposedWord.NOT_A_SEPARATOR); + launchSubActivity(activityClass); + } + + private void launchSubActivity(Class<? extends Activity> activityClass) { Intent intent = new Intent(); - intent.setClass(LatinIME.this, settingsClass); + intent.setClass(LatinIME.this, activityClass); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } diff --git a/java/src/com/android/inputmethod/research/FeedbackActivity.java b/java/src/com/android/inputmethod/research/FeedbackActivity.java new file mode 100644 index 000000000..c9f3b476a --- /dev/null +++ b/java/src/com/android/inputmethod/research/FeedbackActivity.java @@ -0,0 +1,52 @@ +/* + * 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 android.text.Editable; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; + +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 + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + public void onBackPressed() { + ResearchLogger.getInstance().onLeavingSendFeedbackDialog(); + super.onBackPressed(); + } +} diff --git a/java/src/com/android/inputmethod/research/FeedbackFragment.java b/java/src/com/android/inputmethod/research/FeedbackFragment.java new file mode 100644 index 000000000..a2e08e2b7 --- /dev/null +++ b/java/src/com/android/inputmethod/research/FeedbackFragment.java @@ -0,0 +1,73 @@ +/* + * 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.app.Fragment; +import android.os.Bundle; +import android.text.Editable; +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 com.android.inputmethod.latin.R; + +public class FeedbackFragment extends Fragment { + private EditText mEditText; + private CheckBox mCheckBox; + + @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); + mCheckBox = (CheckBox) view.findViewById(R.id.research_feedback_include_history); + + final Button sendButton = (Button) view.findViewById( + R.id.research_feedback_send_button); + sendButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + final Editable editable = mEditText.getText(); + final String feedbackContents = editable.toString(); + final boolean includeHistory = mCheckBox.isChecked(); + ResearchLogger.getInstance().sendFeedback(feedbackContents, includeHistory); + final Activity activity = FeedbackFragment.this.getActivity(); + activity.finish(); + ResearchLogger.getInstance().onLeavingSendFeedbackDialog(); + } + }); + + final Button cancelButton = (Button) view.findViewById( + R.id.research_feedback_cancel_button); + cancelButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + final Activity activity = FeedbackFragment.this.getActivity(); + activity.finish(); + ResearchLogger.getInstance().onLeavingSendFeedbackDialog(); + } + }); + + return view; + } +} diff --git a/java/src/com/android/inputmethod/research/FeedbackLayout.java b/java/src/com/android/inputmethod/research/FeedbackLayout.java new file mode 100644 index 000000000..f2cbfe308 --- /dev/null +++ b/java/src/com/android/inputmethod/research/FeedbackLayout.java @@ -0,0 +1,62 @@ +/* + * 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); + } +} diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index b40bfe387..e6828da50 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -83,7 +83,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String WHITESPACE_SEPARATORS = " \t\n\r"; private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1 private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid"; - private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; + private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; // timeout to notify user private static final ResearchLogger sInstance = new ResearchLogger(); // to write to a different filename, e.g., for testing, set mFile before calling start() @@ -95,7 +95,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // the system to do so. /* package */ ResearchLog mIntentionalResearchLog; // LogUnits are queued here and released only when the user requests the intentional log. - private final List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); + private List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); private boolean mIsPasswordView = false; private boolean mIsLoggingSuspended = false; @@ -268,22 +268,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private void logWholeSessionHistory() throws IOException { - try { - LogUnit headerLogUnit = new LogUnit(); - headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false); - mIntentionalResearchLog.publishAllEvents(headerLogUnit); - for (LogUnit logUnit : mIntentionalResearchLogQueue) { - mIntentionalResearchLog.publishAllEvents(logUnit); - } - mIntentionalResearchLog.stop(); - mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); - mIntentionalResearchLog.start(); - } finally { - mIntentionalResearchLogQueue.clear(); - } - } - private void restart() { stop(); start(); @@ -325,13 +309,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } public void presentResearchDialog(final LatinIME latinIME) { + if (mInFeedbackDialog) { + Toast.makeText(latinIME, R.string.research_please_exit_feedback_form, + Toast.LENGTH_LONG).show(); + return; + } final CharSequence title = latinIME.getString(R.string.english_ime_research_log); final boolean showEnable = mIsLoggingSuspended || !sIsLogging; final CharSequence[] items = new CharSequence[] { - latinIME.getString(R.string.note_timestamp_for_researchlog), - showEnable ? latinIME.getString(R.string.enable_session_logging) : - latinIME.getString(R.string.do_not_log_this_session), - latinIME.getString(R.string.log_whole_session_history) + latinIME.getString(R.string.research_feedback_menu_option), + showEnable ? latinIME.getString(R.string.research_enable_session_logging) : + latinIME.getString(R.string.research_do_not_log_this_session) }; final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override @@ -339,9 +327,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang di.dismiss(); switch (position) { case 0: - userTimestamp(); - Toast.makeText(latinIME, R.string.notify_recorded_timestamp, - Toast.LENGTH_LONG).show(); + presentFeedbackDialog(latinIME); break; case 1: if (showEnable) { @@ -349,11 +335,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang setLoggingAllowed(true); } resumeLogging(); - Toast.makeText(latinIME, R.string.notify_session_logging_enabled, + Toast.makeText(latinIME, + R.string.research_notify_session_logging_enabled, Toast.LENGTH_LONG).show(); } else { Toast toast = Toast.makeText(latinIME, - R.string.notify_session_log_deleting, Toast.LENGTH_LONG); + R.string.research_notify_session_log_deleting, + Toast.LENGTH_LONG); toast.show(); boolean isLogDeleted = abort(); final long currentTime = System.currentTimeMillis(); @@ -361,21 +349,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang SUSPEND_DURATION_IN_MINUTES; suspendLoggingUntil(resumeTime); toast.cancel(); - Toast.makeText(latinIME, R.string.notify_logging_suspended, + Toast.makeText(latinIME, R.string.research_notify_logging_suspended, Toast.LENGTH_LONG).show(); } break; - case 2: - try { - logWholeSessionHistory(); - Toast.makeText(latinIME, R.string.notify_session_history_logged, - Toast.LENGTH_LONG).show(); - } catch (IOException e) { - Toast.makeText(latinIME, R.string.notify_session_history_not_logged, - Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - break; } } @@ -386,6 +363,83 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang latinIME.showOptionDialog(builder.create()); } + private boolean mInFeedbackDialog = false; + public void presentFeedbackDialog(LatinIME latinIME) { + mInFeedbackDialog = true; + latinIME.launchKeyboardedDialogActivity(FeedbackActivity.class); + } + + private ResearchLog mFeedbackLog; + private List<LogUnit> mFeedbackQueue; + private ResearchLog mSavedMainResearchLog; + private ResearchLog mSavedIntentionalResearchLog; + private List<LogUnit> mSavedIntentionalResearchLogQueue; + + private void saveLogsForFeedback() { + mFeedbackLog = mIntentionalResearchLog; + if (mIntentionalResearchLogQueue != null) { + mFeedbackQueue = new ArrayList<LogUnit>(mIntentionalResearchLogQueue); + } else { + mFeedbackQueue = null; + } + mSavedMainResearchLog = mMainResearchLog; + mSavedIntentionalResearchLog = mIntentionalResearchLog; + mSavedIntentionalResearchLogQueue = mIntentionalResearchLogQueue; + + mMainResearchLog = null; + mIntentionalResearchLog = null; + mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); + } + + private static final int LOG_DRAIN_TIMEOUT_IN_MS = 1000 * 5; + public void sendFeedback(final String feedbackContents, final boolean includeHistory) { + if (includeHistory && mFeedbackLog != null) { + try { + LogUnit headerLogUnit = new LogUnit(); + headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false); + mFeedbackLog.publishAllEvents(headerLogUnit); + for (LogUnit logUnit : mFeedbackQueue) { + mFeedbackLog.publishAllEvents(logUnit); + } + userFeedback(mFeedbackLog, feedbackContents); + mFeedbackLog.stop(); + try { + mFeedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); + mIntentionalResearchLog.start(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + mIntentionalResearchLogQueue.clear(); + } + mResearchLogUploader.uploadNow(null); + } else { + // create a separate ResearchLog just for feedback + final ResearchLog feedbackLog = new ResearchLog(createLogFile(mFilesDir)); + try { + feedbackLog.start(); + userFeedback(feedbackLog, feedbackContents); + feedbackLog.stop(); + feedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS); + mResearchLogUploader.uploadNow(null); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void onLeavingSendFeedbackDialog() { + mInFeedbackDialog = false; + mMainResearchLog = mSavedMainResearchLog; + mIntentionalResearchLog = mSavedIntentionalResearchLog; + mIntentionalResearchLogQueue = mSavedIntentionalResearchLogQueue; + } + public void initSuggest(Suggest suggest) { mSuggest = suggest; } @@ -540,7 +594,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return; } if (mMainResearchLog == null) { - Log.w(TAG, "ResearchLog was not properly set up"); return; } if (isPrivacySensitive) { @@ -647,6 +700,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, final SharedPreferences prefs) { final ResearchLogger researchLogger = getInstance(); + if (researchLogger.mInFeedbackDialog) { + researchLogger.saveLogsForFeedback(); + } researchLogger.start(); if (editorInfo != null) { final Context context = researchLogger.mContext; @@ -688,6 +744,20 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang researchLogger.onWordComplete(scrubbedWord); } + private static final String[] EVENTKEYS_USER_FEEDBACK = { + "UserFeedback", "FeedbackContents" + }; + + private void userFeedback(ResearchLog researchLog, String feedbackContents) { + // this method is special; it directs the feedbackContents to a particular researchLog + final LogUnit logUnit = new LogUnit(); + final Object[] values = { + feedbackContents + }; + logUnit.addLogAtom(EVENTKEYS_USER_FEEDBACK, values, false); + researchLog.publishAllEvents(logUnit); + } + // Regular logging methods private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT = { |