1
0
Fork 0

added offical support for Android 15 (upgraded the target and compile SDKs to 35)

This commit is contained in:
sspanak 2024-10-17 11:17:13 +03:00 committed by Dimo Karaivanov
parent d7506e72d9
commit 80d50fb546
14 changed files with 162 additions and 30 deletions

View file

@ -49,7 +49,7 @@ To support a new language one needs to:
- Find a suitable dictionary and add it to the `app/languages/dictionaries/` folder. Two file formats are supported, [see below](#dictionary-formats).
- Do not forget to include the dictionary license (or readme) file in the `docs/` folder.
- Create a new `.yml` file in `app/languages/definitions/` and define the language properties.
- `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text).
- `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk17-suported-locales.html#modules).
- `dictionaryFile` is the name of the dictionary in `app/languages/dictionaries/` folder.
- `layout` contains the letters and punctuation marks associated with each key.
- For 0-key `[SPECIAL]`, will be fine in most languages, but you could define your own set of special characters, for example: `[@, #, $]`.

View file

@ -69,12 +69,12 @@ def getVersionString = { flavor -> return flavor == 'debug' ? getDebugVersion()
android {
namespace PACKAGE_NAME
compileSdk 34
compileSdk 35
defaultConfig {
applicationId PACKAGE_NAME
minSdk 19
targetSdk 34
targetSdk 35
versionCode getVerCode()
versionName getVerName()
}
@ -97,6 +97,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
flavorDimensions = ['app']
productFlavors {

View file

@ -230,6 +230,11 @@ public class TraditionalT9 extends MainViewHandler {
super.onDestroy();
}
@Override
public void onTimeout(int startId) {
onZombie();
super.onTimeout(startId);
}
@Override
protected boolean onNumber(int key, boolean hold, int repeat) {

View file

@ -0,0 +1,38 @@
package io.github.sspanak.tt9.languages;
import androidx.annotation.NonNull;
import java.util.Locale;
/**
* Deals with inconsistencies between Java and Android language codes.
*/
class LocaleCompat {
private final Locale locale;
LocaleCompat(Locale locale) {
this.locale = locale;
}
private String getCountry() {
String country = locale != null ? locale.getCountry() : "";
return country.equals("YI") ? "JI" : country;
}
private String getLanguage() {
String language = locale != null ? locale.getLanguage() : "";
return switch (language) {
case "yi" -> "ji";
case "he" -> "iw";
case "id" -> "in";
default -> language;
};
}
@NonNull
@Override
public String toString() {
return (getLanguage() + getCountry()).toUpperCase();
}
}

View file

@ -134,7 +134,7 @@ public class NaturalLanguage extends Language implements Comparable<NaturalLangu
@Override
public int getId() {
if (id == 0) {
String idString = (locale.getLanguage() + locale.getCountry()).toUpperCase();
String idString = new LocaleCompat(locale).toString();
for (int i = 0; i < idString.length(); i++) {
id |= (idString.codePointAt(i) & 31) << (i * 5);
}
@ -149,14 +149,11 @@ public class NaturalLanguage extends Language implements Comparable<NaturalLangu
return "hi";
}
switch (getLocale().getLanguage()) {
case "fi":
return "su";
case "sw":
return "ki";
default:
return getLocale().toString();
}
return switch (getLocale().getLanguage()) {
case "fi" -> "su";
case "sw" -> "ki";
default -> getLocale().toString();
};
}

View file

@ -60,6 +60,13 @@ public class PreferencesActivity extends ActivityWithNavigation implements Prefe
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
preventEdgeToEdge(findViewById(R.id.preferences_container));
}
@Override
public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, @NonNull Preference pref) {
BaseScreenFragment fragment = getScreen((getScreenName(pref)));
@ -68,6 +75,7 @@ public class PreferencesActivity extends ActivityWithNavigation implements Prefe
return true;
}
@Override
protected void onResume() {
super.onResume();

View file

@ -84,7 +84,6 @@ abstract public class BaseScreenFragment extends PreferenceFragmentCompat {
}
public void resetFontSize(boolean reloadList) {
initPreferencesList();
preferencesList.getAll(reloadList, true);

View file

@ -9,7 +9,6 @@ import android.view.inputmethod.InputConnection;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.util.concurrent.Callable;
@ -17,7 +16,7 @@ import io.github.sspanak.tt9.ime.helpers.Key;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
abstract public class ActivityWithNavigation extends AppCompatActivity {
abstract public class ActivityWithNavigation extends EdgeToEdgeActivity {
public static final String LOG_TAG = ActivityWithNavigation.class.getSimpleName();
protected SettingsStore settings;

View file

@ -0,0 +1,49 @@
package io.github.sspanak.tt9.ui;
import android.os.Build;
import android.view.View;
import android.view.WindowInsets;
import androidx.appcompat.app.AppCompatActivity;
public class EdgeToEdgeActivity extends AppCompatActivity {
public void preventEdgeToEdge(View view) {
if (view == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
return;
}
WindowInsets insets = getInsets(view);
if (insets == null) {
return;
}
view.setPadding(
insets.getStableInsetLeft(),
insets.getStableInsetTop(),
insets.getStableInsetRight(),
insets.getStableInsetBottom()
);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
applyThemeToSystemUi();
}
private void applyThemeToSystemUi() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
getWindow().setStatusBarContrastEnforced(true);
}
}
private WindowInsets getInsets(View view) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return null;
}
WindowInsets newInsets = view != null ? view.getRootWindowInsets() : null;
return newInsets == null ? getWindow().getDecorView().getRootWindowInsets() : newInsets;
}
}

View file

@ -2,19 +2,36 @@ package io.github.sspanak.tt9.ui;
import android.os.Bundle;
import android.util.Base64;
import android.view.View;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
abstract public class WebViewActivity extends AppCompatActivity {
abstract public class WebViewActivity extends EdgeToEdgeActivity implements View.OnAttachStateChangeListener {
private WebView container;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
buildLayout();
}
@Override
public void onViewAttachedToWindow(@NonNull View view) {
preventEdgeToEdge((View) view.getParent());
}
@Override
public void onViewDetachedFromWindow(@NonNull View view) {}
@Override
protected void onDestroy() {
container.removeOnAttachStateChangeListener(this);
super.onDestroy();
}
@Override
public boolean onSupportNavigateUp() {
finish();
@ -35,7 +52,8 @@ abstract public class WebViewActivity extends AppCompatActivity {
}
private void setContent() {
WebView container = new WebView(this);
container = new WebView(this);
container.addOnAttachStateChangeListener(this);
// On API > 30 the WebView does not load the entire String with .loadData(),
// so we need to do this weird shit.

View file

@ -1,8 +1,10 @@
package io.github.sspanak.tt9.ui.main;
import android.os.Build;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import androidx.annotation.NonNull;
@ -60,6 +62,21 @@ abstract class BaseMainLayout {
}
/**
* Calculate the bottom padding for the edge-to-edge mode in Android 15+. Without padding,
* the bottom of the View will be cut off by the system navigation bar.
*/
protected int getBottomInsetSize() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM || tt9 == null) {
return 0;
}
final int DEFAULT_SIZE = 96;
WindowInsets insets = tt9.getWindow().findViewById(android.R.id.content).getRootWindowInsets();
return insets != null ? insets.getStableInsetBottom() : DEFAULT_SIZE;
}
protected void enableClickHandlers() {
for (SoftKey key : getKeys()) {
key.setTT9(tt9);

View file

@ -203,7 +203,8 @@ class MainLayoutNumpad extends BaseMainLayout {
Resources resources = tt9.getResources();
height = getKeyHeightCompat() * 4
+ resources.getDimensionPixelSize(R.dimen.numpad_candidate_height)
+ resources.getDimensionPixelSize(R.dimen.numpad_padding_bottom) * 4;
+ Math.round(resources.getDimension(R.dimen.numpad_padding_bottom))
+ getBottomInsetSize();
}
return height;

View file

@ -25,7 +25,7 @@ class MainLayoutTray extends BaseMainLayout {
int getHeight(boolean forceRecalculate) {
if (height <= 0 || forceRecalculate) {
Resources resources = tt9.getResources();
height = resources.getDimensionPixelSize(R.dimen.candidate_height);
height = resources.getDimensionPixelSize(R.dimen.candidate_height) + getBottomInsetSize();
if (isCommandPaletteShown() || isTextEditingPaletteShown()) {
height += resources.getDimensionPixelSize(R.dimen.numpad_key_height);

View file

@ -1,5 +1,6 @@
package io.github.sspanak.tt9.ui.main;
import android.os.Build;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@ -29,9 +30,11 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
private void calculateSnapHeights() {
heightNumpad = new MainLayoutNumpad(tt9).getHeight();
heightSmall = new MainLayoutSmall(tt9).getHeight();
heightTray = new MainLayoutTray(tt9).getHeight();
boolean forceRecalculate = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM;
heightNumpad = new MainLayoutNumpad(tt9).getHeight(forceRecalculate);
heightSmall = new MainLayoutSmall(tt9).getHeight(forceRecalculate);
heightTray = new MainLayoutTray(tt9).getHeight(forceRecalculate);
}
@ -55,13 +58,7 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
}
}
private void onCreateAdjustHeight() {
if (tt9.getSettings().isMainLayoutNumpad() && height > heightSmall && height <= heightNumpad) {
setHeight(height, heightSmall, heightNumpad);
}
}
@Override public void onViewAttachedToWindow(@NonNull View v) { onCreateAdjustHeight(); }
@Override public void onViewAttachedToWindow(@NonNull View v) { setHeight(height, heightSmall, heightNumpad); }
@Override public void onViewDetachedFromWindow(@NonNull View v) {}