Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa07f9ea authored by Frank Preel's avatar Frank Preel Committed by Nishith Khanna
Browse files

Add an icon on the keyboard to give access to the STT feature

parent 23a27ace
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
    android:viewportWidth="22.97"
    android:viewportHeight="31.17"
    android:width="22.97dp"
    android:height="31.17dp">
    <path
        android:pathData="M11.48 19.69c2.72 0 4.91 -2.2 4.91 -4.92l0.02 -9.84c0 -2.72 -2.2 -4.92 -4.92 -4.92s-4.92 2.2 -4.92 4.92v9.84c0 2.72 2.2 4.92 4.92 4.92ZM20.18 14.77c0 4.92 -4.17 8.37 -8.7 8.37S2.79 19.69 2.79 14.77H0c0 5.59 4.46 10.22 9.84 11.03v5.38h3.28v-5.38c5.38 -0.79 9.84 -5.41 9.84 -11.03h-2.79Z"
        android:fillColor="#DEADB5B9" />
</vector>
 No newline at end of file
+39 −19
Original line number Diff line number Diff line
@@ -18,10 +18,15 @@
*/
-->

<LinearLayout
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:orientation="vertical">

@@ -43,3 +48,18 @@
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <ImageButton
        android:id="@+id/floating_button"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_gravity="top|end"
        android:layout_marginTop="-4dp"
        android:layout_marginEnd="4dp"
        android:background="@android:color/transparent"
        android:src="@drawable/ic_ime_switch"
        android:contentDescription="@string/ime_switch_button"
        android:focusable="true"
        android:clickable="true" />

</FrameLayout>
+19 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright Murena SAS 2025
  ~ This program is free software: you can redistribute it and/or modify
  ~ it under the terms of the GNU General Public License as published by
  ~ the Free Software Foundation, either version 3 of the License, or
  ~ (at your option) any later version.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  ~ GNU General Public License for more details.
  ~
  ~ You should have received a copy of the GNU General Public License
  ~  along with this program.  If not, see <https://www.gnu.org/licenses/>.
  -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="ime_switch_button">Speech to text</string>
</resources>
+57 −0
Original line number Diff line number Diff line
@@ -23,6 +23,10 @@ import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROP
import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;

import android.Manifest.permission;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.pm.PackageManager;
import androidx.core.content.ContextCompat;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@@ -56,7 +60,10 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.ImageButton;

import androidx.annotation.NonNull;

@@ -105,6 +112,10 @@ import com.android.inputmethod.latin.utils.StatsUtilsManager;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import com.android.inputmethod.latin.utils.ViewLayoutUtils;

import android.content.ContentResolver;

import foundation.e.stt.AccountInfoContentProvider;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -132,6 +143,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen

    private static final int MAX_SPACESLIDE_CHARS = 32;

    private static final String KEY_STT_KEYBOARD = "foundation.e.stt/.MurenaWhisperInputService";

    /**
     * A broadcast intent action to hide the software keyboard.
     */
@@ -211,6 +224,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen

    public final UIHandler mHandler = new UIHandler(this);

    private ImageButton floatingButton;

    public static final class UIHandler extends LeakGuardHandlerWrapper<LatinIME> {
        private static final int MSG_UPDATE_SHIFT_STATE = 0;
        private static final int MSG_PENDING_IMS_CALLBACK = 1;
@@ -858,6 +873,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                mIsHardwareAcceleratedDrawingEnabled);
    }

    private boolean isSttKeyboardActivated() {
        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        List<InputMethodInfo> enabledImeList = inputMethodManager.getEnabledInputMethodList();
        for (InputMethodInfo inputMethodInfo : enabledImeList) {
            if (inputMethodInfo.getId().equals(KEY_STT_KEYBOARD)) {
                return true;
            }
        }
        return false;
    }

    private void switchToSttIme() {
        if (isSttKeyboardActivated()) {
            switchInputMethod(KEY_STT_KEYBOARD);
        }
    }

    @Override
    public void setInputView(final View view) {
        super.setInputView(view);
@@ -868,6 +900,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        if (hasSuggestionStripView()) {
            mSuggestionStripView.setListener(this, view);
        }

        floatingButton = mInputView.findViewById(R.id.floating_button);
        floatingButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switchToSttIme();
            }
        });
        manageFloatingButtonVisibility();
    }

    private void manageFloatingButtonVisibility() {
        if (shouldShowFloatingButton()) {
            floatingButton.setVisibility(View.VISIBLE);
        } else {
            floatingButton.setVisibility(View.GONE);
        }
    }

    private boolean shouldShowFloatingButton() {
        return AccountInfoContentProvider.isPremiumAccount(getApplicationContext()) && isSttKeyboardActivated();
    }

    @Override
@@ -884,6 +937,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
    public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) {
        mHandler.onStartInputView(editorInfo, restarting);
        mStatsUtilsManager.onStartInputView();

        if (floatingButton != null) {
            manageFloatingButtonVisibility();
        }
    }

    @Override
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 MURENA SAS
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 *
 */
package foundation.e.stt; 

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.content.Context;
import android.util.Log;

public class AccountInfoContentProvider {

    private static final String TAG = "AccountInfoContentProvider";
    private static final Uri ACCOUNT_URI = Uri.parse("content://foundation.e.stt.provider/account");
    private static final String COLUMN_IS_PREMIUM = "is_premium";
    private static final int PREMIUM_VALUE = 1;

    public static boolean isPremiumAccount(Context context) {
        Cursor cursor = null;
        try {
            ContentResolver resolver = context.getContentResolver();
            String[] projection = new String[] { COLUMN_IS_PREMIUM };
            cursor = resolver.query(ACCOUNT_URI, projection, null, null, null);

            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndex(COLUMN_IS_PREMIUM);
                if (columnIndex != -1) {
                    int value = cursor.getInt(columnIndex);
                    return value == PREMIUM_VALUE;
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "Error failed to read status", e);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return false;
    }
}
 No newline at end of file