diff --git a/android/KMAPro/kMAPro/build.gradle b/android/KMAPro/kMAPro/build.gradle
index 77ab2fa736..766e2cd417 100644
--- a/android/KMAPro/kMAPro/build.gradle
+++ b/android/KMAPro/kMAPro/build.gradle
@@ -32,7 +32,7 @@ android {
defaultConfig {
applicationId "com.tavultesoft.kmapro"
- minSdkVersion 21
+ minSdkVersion 23
targetSdkVersion 35
//println "===DUMPING PROPERTIES==="
@@ -184,6 +184,7 @@ dependencies {
implementation ('com.github.kenglxn.QRGen:android:3.0.1') {
transitive = true
}
+ implementation 'com.google.android.gms:play-services-maps3d:0.2.0'
}
/*def void dumpProperties(it){
diff --git a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java
deleted file mode 100644
index 16330bfcda..0000000000
--- a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/**
- * Copyright (C) 2017 SIL International. All rights reserved.
- */
-
-package com.keyman.android;
-
-import com.keyman.engine.util.DownloadFileUtils;
-import com.tavultesoft.kmapro.BuildConfig;
-import com.tavultesoft.kmapro.DefaultLanguageResource;
-import com.tavultesoft.kmapro.KeymanSettingsActivity;
-import com.tavultesoft.kmapro.PreferencesManager;
-import com.keyman.engine.KMManager;
-import com.keyman.engine.KMManager.KeyboardType;
-import com.keyman.engine.KMHardwareKeyboardInterpreter;
-import com.keyman.engine.KMManager.SuggestionType;
-import com.keyman.engine.KeyboardEventHandler.OnKeyboardEventListener;
-import com.keyman.engine.R;
-import com.keyman.engine.data.Keyboard;
-import com.keyman.engine.util.DependencyUtil;
-import com.keyman.engine.util.DependencyUtil.LibraryType;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.graphics.Point;
-import android.inputmethodservice.InputMethodService;
-import android.text.InputType;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputConnection;
-import android.widget.FrameLayout;
-import android.content.Intent;
-
-import io.sentry.android.core.SentryAndroid;
-import io.sentry.Sentry;
-
-public class SystemKeyboard extends InputMethodService implements OnKeyboardEventListener {
-
- private static View inputView = null;
- private KMHardwareKeyboardInterpreter interpreter = null;
- private int inputType = InputType.TYPE_NULL;
- private int lastOrientation = Configuration.ORIENTATION_UNDEFINED;
-
- private static final String TAG = "SystemKeyboard";
-
- /**
- * Main initialization of the input method component. Be sure to call
- * to super class.
- */
- @Override
- public void onCreate() {
- super.onCreate();
-
- if (DependencyUtil.libraryExists(LibraryType.SENTRY) && !Sentry.isEnabled()) {
- Log.d(TAG, "Initializing Sentry");
- SentryAndroid.init(getApplicationContext(), options -> {
- options.setEnableAutoSessionTracking(false);
- options.setRelease(com.tavultesoft.kmapro.BuildConfig.KEYMAN_VERSION_GIT_TAG);
- options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.KEYMAN_VERSION_ENVIRONMENT);
- });
- }
- if (BuildConfig.DEBUG) {
- KMManager.setDebugMode(true);
- }
- KMManager.addKeyboardEventListener(this);
- Context context = getApplicationContext();
- KMManager.initialize(context, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- DefaultLanguageResource.install(context);
- interpreter = new KMHardwareKeyboardInterpreter(context, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- KMManager.setInputMethodService(this); // for HW interface
-
- SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
- KMManager.SpacebarText spacebarText = KMManager.SpacebarText.fromString(prefs.getString(KeymanSettingsActivity.spacebarTextKey, KMManager.SpacebarText.LANGUAGE_KEYBOARD.toString()));
- KMManager.setSpacebarText(spacebarText);
-
- // Set the system keyboard HTML banner
- BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
-
- boolean mayHaveHapticFeedback = prefs.getBoolean(KeymanSettingsActivity.hapticFeedbackKey, false);
- KMManager.setHapticFeedback(mayHaveHapticFeedback);
-
- // Checking for updates should never be allowed to crash the keyboard.
- // Just silently fail if this occurs.
- if(DownloadFileUtils.getDownloadManager(this) != null) {
- // Will try to emit a toast if it fails - i.e., is not silent.
- KMManager.executeResourceUpdate(this);
- }
- }
-
- @Override
- public void onDestroy() {
- inputView = null;
- KMManager.removeKeyboardEventListener(this);
- interpreter = null; // Throw it away, since we're losing our application's context.
- KMManager.onDestroy();
- super.onDestroy();
- }
-
- /**
- * This is the point where you can do all of your UI initialization. It
- * is called after creation and any configuration change.
- */
- @Override
- public void onInitializeInterface() {
- super.onInitializeInterface();
- }
-
- /**
- * Called by the framework when your view for creating input needs to
- * be generated. This will be called the first time your input method
- * is displayed, and every time it needs to be re-created such as due to
- * a configuration change.
- */
- @Override
- public View onCreateInputView() {
- if (inputView == null) {
- inputView = KMManager.createInputView(this);
- }
-
- ViewGroup parent = (ViewGroup) inputView.getParent();
- if (parent != null) {
- parent.removeView(inputView);
- }
-
- return inputView;
- }
-
- /**
- * Deal with the editor reporting movement of its cursor.
- */
- @Override
- public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
- super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd);
- KMManager.updateSelectionRange(KMManager.KeyboardType.KEYBOARD_TYPE_SYSTEM);
- }
-
- private void sendCurrentFontName() {
- Keyboard keyboardInfo = KMManager.getCurrentKeyboardInfo(this);
- if (keyboardInfo != null) {
- String fontName = keyboardInfo.getFont();
-
- Intent intent;
- if (BuildConfig.DEBUG) {
- intent = new Intent("com.tavultesoft.kmapro.debug.keyboard_changed");
- } else {
- intent = new Intent("com.tavultesoft.kmapro.keyboard_changed");
- }
- intent.putExtra("fontName", fontName);
- sendBroadcast(intent);
- }
- }
-
- /**
- * This is the main point where we do our initialization of the input method
- * to begin operating on an application. At this point we have been
- * bound to the client, and are now receiving all of the detailed information
- * about the target of our edits.
- */
- @Override
- public void onStartInput(EditorInfo attribute, boolean restarting) {
- attribute.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_FLAG_NO_FULLSCREEN;
- super.onStartInput(attribute, restarting);
- KMManager.onStartInput(attribute, restarting);
- KMManager.resetContext(KeyboardType.KEYBOARD_TYPE_SYSTEM);
-
- Context appContext = getApplicationContext();
- // Temporarily disable predictions on certain fields (e.g. hidden password field or numeric)
- inputType = attribute.inputType;
- KMManager.setPredictionsSuspended(inputType, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- if (KMManager.getPredictionsSuspended(KeyboardType.KEYBOARD_TYPE_SYSTEM)) {
- KMManager.setBannerOptions(false);
- // Set the system keyboard HTML banner
- BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- } else if (KMManager.isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM)){
- // Check if predictions needs to be re-enabled per Settings preference
- Keyboard kbInfo = KMManager.getCurrentKeyboardInfo(appContext);
- if (kbInfo != null) {
- String langId = kbInfo.getLanguageID();
- SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
- int maySuggest = prefs.getInt(KMManager.getLanguageAutoCorrectionPreferenceKey(langId), KMManager.KMDefault_Suggestion);
- // Enable banner if maySuggest is not SuggestionType.SUGGESTIONS_DISABLED (0)
- KMManager.setBannerOptions(maySuggest != SuggestionType.SUGGESTIONS_DISABLED.toInt());
- } else {
- KMManager.setBannerOptions(false);
- }
- }
-
- // Determine special handling for ENTER key
- KMManager.setEnterMode(attribute.imeOptions, inputType);
-
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
- /*
- We do sometimes receive null `icText.text`, even though
- getExtractedText() docs does not list this as a possible
- return value, so we test for that as well (#11479)
- */
- if (icText != null && icText.text != null) {
- // Update the text selection but ignore the returned statuses
- KMManager.updateText(KeyboardType.KEYBOARD_TYPE_SYSTEM, icText.text.toString());
- KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_SYSTEM);
- }
- }
-
- // Select numeric layer if applicable
- if (KMManager.isNumericField(inputType)) {
- KMManager.setNumericLayer(KeyboardType.KEYBOARD_TYPE_SYSTEM);
- }
-
- if (KMManager.isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM)) {
- sendCurrentFontName();
- }
- }
-
- @Override
- public void onStartInputView(EditorInfo attribute, boolean restarting) {
- super.onStartInputView(attribute, restarting);
- setInputView(onCreateInputView());
-
- // Update the input type
- inputType = attribute.inputType;
- }
-
- @Override
- public void onUpdateExtractingVisibility(EditorInfo ei) {
- super.onUpdateExtractingVisibility(ei);
- }
-
- @Override
- public void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly) {
- super.onConfigureWindow(win, isFullscreen, isCandidatesOnly);
-
- // We don't currently use isFullscreen or isCandidatesOnly; we always want to MATCH_PARENT,
- // unlike the default for height which is WRAP_CONTENT. We then adjust the touchable area
- // in `onCalculateInsets`
- win.setLayout(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
- }
-
- @Override
- public void onComputeInsets(InputMethodService.Insets outInsets) {
- super.onComputeInsets(outInsets);
-
- // This method (likely) includes the IME equivalent to `onResume` for `Activity`-based classes,
- // making it an important time to detect orientation changes.
- Context appContext = getApplicationContext();
- int newOrientation = KMManager.getOrientation(appContext);
- if(newOrientation != lastOrientation) {
- lastOrientation = newOrientation;
- Configuration newConfig = this.getResources().getConfiguration();
- KMManager.onConfigurationChanged(newConfig);
- }
-
- // Update the touchable region of the Keyman keyboard
- Point size = KMManager.getWindowSize(getApplicationContext());
-
- int inputViewHeight = 0;
- if (inputView != null) {
- inputViewHeight = inputView.getHeight();
- }
-
- int navigationHeight = KMManager.getNavigationBarHeight(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- int bannerHeight = KMManager.getBannerHeight(this);
- int kbHeight = KMManager.getKeyboardHeight(this);
- outInsets.contentTopInsets = inputViewHeight - bannerHeight - kbHeight - navigationHeight;
- outInsets.visibleTopInsets = outInsets.contentTopInsets;
- outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
- outInsets.touchableRegion.set(0, outInsets.contentTopInsets, size.x, size.y);
- }
-
- @Override
- public void onKeyboardLoaded(KeyboardType keyboardType) {
- // Do nothing
- }
-
- @Override
- public void onKeyboardChanged(String newKeyboard) {
- // Refresh banner theme
- BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- KMManager.showSystemKeyboard();
- sendCurrentFontName();
- }
-
- @Override
- public void onKeyboardShown() {
- // Refresh banner theme
- BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
- }
-
- @Override
- public void onKeyboardDismissed() {
- // Do nothing
- }
-
- @Override
- public boolean onEvaluateInputViewShown() {
- // On Android API 36+, the OSK defaults to not appearing when a physical keyboard is connected.
- // If the default implementation returns true, recommend honoring it
- // Reference: https://android.googlesource.com/platform/frameworks/base/+/7b739a8%5E%21/
- if (super.onEvaluateInputViewShown()) {
- return true;
- };
-
- Context context = getApplicationContext();
- SharedPreferences prefs = context.getSharedPreferences(PreferencesManager.kma_prefs_name, Context.MODE_PRIVATE);
- boolean showOSK = prefs.getBoolean(KeymanSettingsActivity.oskWithPhysicalKeyboardKey, false);
- return showOSK;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- // Determine if Physical keystroke should be passed off
- if (inputType == InputType.TYPE_NULL) {
- return false; // Revert to default handling
- }
-
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_BACK:
- // Dismiss the keyboard if currently shown
- if (isInputViewShown()) {
- KMManager.hideSystemKeyboard();
- return true;
- }
- break;
- }
- }
-
- return interpreter.onKeyDown(keyCode, event); // if false, will revert to default handling.
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return interpreter.onKeyUp(keyCode, event);
- }
-
- @Override
- public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
- return interpreter.onKeyMultiple(keyCode, count, event);
- }
-
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- return interpreter.onKeyLongPress(keyCode, event);
- }
-}
\ No newline at end of file
diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java
index 8b0ea603b1..726e6db829 100644
--- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java
+++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java
@@ -25,6 +25,7 @@ import com.keyman.engine.KMHelpFileActivity;
import com.keyman.engine.KMKeyboardDownloaderActivity;
import com.keyman.engine.KMManager;
import com.keyman.engine.KMManager.KeyboardType;
+import com.keyman.engine.KeyboardEventHandler;
import com.keyman.engine.KmpInstallMode;
import com.keyman.engine.KMTextView;
import com.keyman.engine.KeyboardEventHandler.OnKeyboardDownloadEventListener;
@@ -59,7 +60,13 @@ import android.os.ParcelFileDescriptor;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.widget.Toolbar;
+import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.app.AlertDialog;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.content.ClipData;
@@ -80,6 +87,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
+import androidx.drawerlayout.widget.DrawerLayout;
import androidx.drawerlayout.widget.DrawerLayout;
@@ -94,18 +102,33 @@ import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.Button;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
+import android.view.Gravity;
+import android.view.inputmethod.InputMethodManager;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import com.google.android.material.navigation.NavigationView;
+import androidx.core.view.GravityCompat;
+import android.view.MenuItem;
+import androidx.appcompat.widget.AppCompatCheckBox;
+
import io.sentry.android.core.SentryAndroid;
public class MainActivity extends BaseActivity implements OnKeyboardEventListener, OnKeyboardDownloadEventListener,
ActivityCompat.OnRequestPermissionsResultCallback {
public static Context context;
+ private DrawerLayout drawerLayout;
+ private ActionBarDrawerToggle drawerToggle;
+ private NavigationView navigationView;
+
// Fields used for installing kmp packages
public static final int PERMISSION_REQUEST_STORAGE = 0;
public static final int READ_REQUEST_CODE = 42;
@@ -175,6 +198,15 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
+ getSupportActionBar().setDisplayShowTitleEnabled(true);
+// ImageView logo = new ImageView(this);
+// logo.setImageResource(R.drawable.keyman_logo);
+// Toolbar.LayoutParams params = new Toolbar.LayoutParams(
+// Toolbar.LayoutParams.WRAP_CONTENT,
+// Toolbar.LayoutParams.WRAP_CONTENT,
+// Gravity.CENTER
+// );
+// toolbar.addView(logo, params);
getSupportActionBar().setLogo(R.drawable.keyman_logo);
getSupportActionBar().setDisplayUseLogoEnabled(false);
@@ -188,6 +220,82 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setBackgroundDrawable(getActionBarDrawable(this));
+ drawerLayout = findViewById(R.id.drawer_layout);
+ drawerLayout.setScrimColor(Color.parseColor("#80000000"));
+ // Initialize drawerToggle WITHOUT toolbar to prevent it from showing up at the start
+ drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open , R.string.drawer_close);
+ drawerLayout.addDrawerListener(drawerToggle);
+ drawerToggle.syncState();
+
+ navigationView = findViewById(R.id.nav_view);
+ navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
+ @Override
+ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+ int id = item.getItemId();
+ if (id == R.id.nav_toggle_show_osk || id == R.id.nav_toggle_haptic_feedback || id == R.id.nav_toggle_send_crash_report) {
+ toggleDrawerSwitch(navigationView, id);
+ } else if (id == R.id.nav_checkbox_enable_system_keyboard) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
+ } else if (id == R.id.nav_checkbox_set_default_keyboard) {
+ drawerLayout.closeDrawers();
+ InputMethodManager imManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imManager != null) {
+ imManager.showInputMethodPicker();
+ }
+ } else if (id == R.id.nav_installed_languages) {
+ drawerLayout.closeDrawers();
+ Intent intent = new Intent(context, LanguagesSettingsActivity.class);
+ intent.putExtra(KMManager.KMKey_DisplayKeyboardSwitcher, false);
+ startActivity(intent);
+ } else if (id == R.id.nav_install_keyboard) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(context, KeymanSettingsInstallActivity.class));
+ } else if (id == R.id.nav_display_language) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(context, KeymanSettingsLocalizeActivity.class));
+ } else if (id == R.id.nav_keyboard_height) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(context, AdjustKeyboardHeightActivity.class));
+ } else if (id == R.id.nav_longpress_delay) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(context, AdjustLongpressDelayActivity.class));
+ } else if (id == R.id.nav_settings) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(context, KeymanSettingsActivity.class));
+ } else if (id == R.id.nav_about) {
+ drawerLayout.closeDrawers();
+ startActivity(new Intent(context, InfoActivity.class));
+ }
+ return true;
+ }
+ });
+ initializeDrawerToggleOptions(navigationView);
+ initializeDrawerCheckboxOptions(navigationView);
+ refreshDrawerSystemKeyboardCheckboxes(navigationView);
+
+ drawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
+
+ @Override
+ public void onDrawerSlide(View drawerView, float slideOffset) {
+ KMManager.hideSystemKeyboard();
+ textView.dismissKeyboard();
+ }
+ @Override
+ public void onDrawerOpened(View drawerView) {
+
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ textView.callOnClick();
+ }
+ });
+
+ drawerToggle.getDrawerArrowDrawable().setColor(Color.BLACK);
+ drawerToggle.getDrawerArrowDrawable().setBarThickness(10f);
+ drawerToggle.getDrawerArrowDrawable().setGapSize(10f);
+
textView = (KMTextView) findViewById(R.id.kmTextView);
textView.setText(prefs.getString(userTextKey, ""));
textSize = prefs.getInt(userTextSizeKey, minTextSize);
@@ -254,6 +362,10 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
protected void onResume() {
super.onResume();
+ if (navigationView != null) {
+ refreshDrawerSystemKeyboardCheckboxes(navigationView);
+ }
+
if (textView != null) {
// Reset inAppPredictionsSuspendedForSensitiveInput flag
KMManager.setPredictionsSuspended(textView.getInputType(), KeyboardType.KEYBOARD_TYPE_INAPP);
@@ -481,6 +593,14 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
_keyboardupdate.setVisible(false);
}
+ return true;
+ } else if (item.getItemId() == R.id.action_overflow) {
+ // Open the drawer from the end when the hamburger (overflow) icon is clicked
+ if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
+ drawerLayout.closeDrawer(GravityCompat.END);
+ } else {
+ drawerLayout.openDrawer(GravityCompat.END);
+ }
return true;
} else {
return super.onOptionsItemSelected(item);
@@ -491,7 +611,11 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
public boolean onKeyUp(int keycode, KeyEvent e) {
switch (keycode) {
case KeyEvent.KEYCODE_MENU:
- menu.performIdentifierAction(R.id.action_overflow, Menu.FLAG_PERFORM_NO_CLOSE);
+ if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
+ drawerLayout.closeDrawer(GravityCompat.END);
+ } else {
+ drawerLayout.openDrawer(GravityCompat.END);
+ }
return true;
}
@@ -980,6 +1104,180 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
startActivity(settingsIntent);
}
+ private void initializeDrawerToggleOptions(NavigationView navigationView) {
+ SharedPreferences prefs = getSharedPreferences(getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
+
+ bindDrawerSwitch(navigationView, R.id.nav_toggle_show_osk,
+ prefs.getBoolean(KeymanSettingsActivity.oskWithPhysicalKeyboardKey, false),
+ new SwitchChangeHandler() {
+ @Override
+ public void onChanged(boolean isChecked) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(KeymanSettingsActivity.oskWithPhysicalKeyboardKey, isChecked);
+ editor.apply();
+ }
+ });
+
+ bindDrawerSwitch(navigationView, R.id.nav_toggle_haptic_feedback,
+ prefs.getBoolean(KeymanSettingsActivity.hapticFeedbackKey, false),
+ new SwitchChangeHandler() {
+ @Override
+ public void onChanged(boolean isChecked) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(KeymanSettingsActivity.hapticFeedbackKey, isChecked);
+ editor.apply();
+ KMManager.setHapticFeedback(isChecked);
+ }
+ });
+
+ bindDrawerSwitch(navigationView, R.id.nav_toggle_send_crash_report,
+ prefs.getBoolean(KeymanSettingsActivity.sendCrashReport, true),
+ new SwitchChangeHandler() {
+ @Override
+ public void onChanged(boolean isChecked) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(KeymanSettingsActivity.sendCrashReport, isChecked);
+ editor.apply();
+ KMManager.setMaySendCrashReport(isChecked);
+ }
+ });
+ }
+
+ private void initializeDrawerCheckboxOptions(NavigationView navigationView) {
+ bindDrawerCheckboxAction(navigationView, R.id.nav_checkbox_enable_system_keyboard,
+ new Runnable() {
+ @Override
+ public void run() {
+ startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
+ }
+ });
+
+ bindDrawerCheckboxAction(navigationView, R.id.nav_checkbox_set_default_keyboard,
+ new Runnable() {
+ @Override
+ public void run() {
+ InputMethodManager imManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imManager != null) {
+ imManager.showInputMethodPicker();
+ }
+ }
+ });
+ }
+
+ private void refreshDrawerSystemKeyboardCheckboxes(NavigationView navigationView) {
+ setDrawerCheckboxState(navigationView, R.id.nav_checkbox_enable_system_keyboard,
+ SystemIMESettings.isEnabledAsSystemKB(context));
+ setDrawerCheckboxState(navigationView, R.id.nav_checkbox_set_default_keyboard,
+ SystemIMESettings.isDefaultKB(context));
+ }
+
+ private void bindDrawerSwitch(NavigationView navigationView, int menuItemId, boolean defaultValue,
+ final SwitchChangeHandler switchChangeHandler) {
+ MenuItem menuItem = navigationView.getMenu().findItem(menuItemId);
+ if (menuItem == null) {
+ return;
+ }
+
+ menuItem.setCheckable(false);
+
+ View actionView = menuItem.getActionView();
+ if (actionView == null) {
+ return;
+ }
+
+ final SwitchCompat switchView;
+ if (actionView instanceof SwitchCompat) {
+ switchView = (SwitchCompat) actionView;
+ } else {
+ switchView = actionView.findViewById(R.id.nav_switch);
+ }
+
+ if (switchView == null) {
+ return;
+ }
+
+ switchView.setChecked(defaultValue);
+ switchView.setOnCheckedChangeListener((buttonView, isChecked) -> switchChangeHandler.onChanged(isChecked));
+ actionView.setOnClickListener(v -> switchView.toggle());
+ }
+
+ private void toggleDrawerSwitch(NavigationView navigationView, int menuItemId) {
+ MenuItem menuItem = navigationView.getMenu().findItem(menuItemId);
+ if (menuItem == null) {
+ return;
+ }
+
+ View actionView = menuItem.getActionView();
+ if (actionView == null) {
+ return;
+ }
+
+ if (actionView instanceof SwitchCompat) {
+ ((SwitchCompat) actionView).toggle();
+ return;
+ }
+
+ SwitchCompat switchView = actionView.findViewById(R.id.nav_switch);
+ if (switchView != null) {
+ switchView.toggle();
+ }
+ }
+
+ private void bindDrawerCheckboxAction(NavigationView navigationView, int menuItemId, final Runnable onActivate) {
+ MenuItem menuItem = navigationView.getMenu().findItem(menuItemId);
+ if (menuItem == null) {
+ return;
+ }
+
+ menuItem.setCheckable(false);
+
+ View actionView = menuItem.getActionView();
+ if (actionView == null) {
+ return;
+ }
+
+ final AppCompatCheckBox checkBox;
+ if (actionView instanceof AppCompatCheckBox) {
+ checkBox = (AppCompatCheckBox) actionView;
+ } else {
+ checkBox = actionView.findViewById(R.id.nav_checkbox);
+ }
+
+ if (checkBox == null) {
+ return;
+ }
+
+ checkBox.setOnClickListener(v -> onActivate.run());
+ actionView.setOnClickListener(v -> onActivate.run());
+ }
+
+ private void setDrawerCheckboxState(NavigationView navigationView, int menuItemId, boolean isChecked) {
+ MenuItem menuItem = navigationView.getMenu().findItem(menuItemId);
+ if (menuItem == null) {
+ return;
+ }
+
+ View actionView = menuItem.getActionView();
+ if (actionView == null) {
+ return;
+ }
+
+ AppCompatCheckBox checkBox;
+ if (actionView instanceof AppCompatCheckBox) {
+ checkBox = (AppCompatCheckBox) actionView;
+ } else {
+ checkBox = actionView.findViewById(R.id.nav_checkbox);
+ }
+
+ if (checkBox != null) {
+ checkBox.setChecked(isChecked);
+ }
+ }
+
+ private interface SwitchChangeHandler {
+ void onChanged(boolean isChecked);
+ }
+
/**
* Dismiss the download progress dialog
*/
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml
index ffcd4a2421..e31fa00e0c 100644
--- a/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml
+++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_main.xml
@@ -1,42 +1,62 @@
-
+ android:fitsSystemWindows="true">
-
-
-
+ android:layout_height="match_parent"
+ android:layout_above="@+id/KMKeyboard"
+ android:orientation="vertical"
+ android:background="@android:color/white"
+ tools:context=".MainActivity"
+ android:fitsSystemWindows="true">
-
+
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/nav_checkbox_item.xml b/android/KMAPro/kMAPro/src/main/res/layout/nav_checkbox_item.xml
new file mode 100644
index 0000000000..6988d63664
--- /dev/null
+++ b/android/KMAPro/kMAPro/src/main/res/layout/nav_checkbox_item.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/nav_divider.xml b/android/KMAPro/kMAPro/src/main/res/layout/nav_divider.xml
new file mode 100644
index 0000000000..192100c926
--- /dev/null
+++ b/android/KMAPro/kMAPro/src/main/res/layout/nav_divider.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/nav_header.xml b/android/KMAPro/kMAPro/src/main/res/layout/nav_header.xml
new file mode 100644
index 0000000000..a59be8fd9d
--- /dev/null
+++ b/android/KMAPro/kMAPro/src/main/res/layout/nav_header.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/nav_switch_item.xml b/android/KMAPro/kMAPro/src/main/res/layout/nav_switch_item.xml
new file mode 100644
index 0000000000..af00b3fe78
--- /dev/null
+++ b/android/KMAPro/kMAPro/src/main/res/layout/nav_switch_item.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/android/KMAPro/kMAPro/src/main/res/menu/main.xml b/android/KMAPro/kMAPro/src/main/res/menu/main.xml
index 7f26efbf81..d98360a9a9 100644
--- a/android/KMAPro/kMAPro/src/main/res/menu/main.xml
+++ b/android/KMAPro/kMAPro/src/main/res/menu/main.xml
@@ -4,19 +4,24 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
-
+
+
+
+
-
+
+
+
+
+
-
-