1
0
mirror of https://gitlab.com/neothefox/LayTray synced 2026-06-13 14:30:49 +03:00

Initial commit - beta1

This commit is contained in:
2018-07-05 23:39:32 +03:00
commit 08b2370f47
33 changed files with 699 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "space.neothefox.laytray"
minSdkVersion 25
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '28.0.1'
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:design:26.1.0'
implementation 'com.github.javadev:underscore:1.34'
}
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="space.neothefox.laytray">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".IconService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"></action>
</intent-filter>
</service>
</application>
</manifest>
@@ -0,0 +1,109 @@
package space.neothefox.laytray;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Icon;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import java.util.HashMap;
import java.util.Map;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
public class IconService extends AccessibilityService
implements SharedPreferences.OnSharedPreferenceChangeListener{
public String TAG = "layicon";
private final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
//Map<CharSequence, String> layoutText = new HashMap<>();
SharedPreferences layouts;
NotificationManager iconManager;
@Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.d(TAG, "Icon service started");
serviceInfo.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
serviceInfo.packageNames = new String[] {"com.blackberry.keyboard"};
serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_VISUAL;
serviceInfo.notificationTimeout = 100;
this.setServiceInfo(serviceInfo);
layouts = getSharedPreferences("layouts", 0);
iconManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//layoutText.put("Русский", "RU");
//layoutText.put("Буквы (АБВ)", "EN");
}
protected void updateNotification(String toast)
{
Notification icon;
Icon smallIcon = Icon.createWithBitmap(textAsBitmap(layouts.getString(toast, "??"), 30, Color.WHITE));
icon = new Notification.Builder(this)
.setSmallIcon(smallIcon)
.setContentTitle(toast)
.setOngoing(true)
.build();
iconManager.notify(0, icon);
return;
}
//Borrowed from Ted Hopp from StackOverflow
public Bitmap textAsBitmap(String text, float textSize, int textColor) {
Paint paint = new Paint(ANTI_ALIAS_FLAG);
paint.setTextSize(textSize);
paint.setColor(textColor);
paint.setTextAlign(Paint.Align.LEFT);
float baseline = -paint.ascent(); // ascent() is negative
int width = (int) (paint.measureText(text) + 0.5f); // round
int height = (int) (baseline + paint.descent() + 0.5f);
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawText(text, 0, baseline, paint);
return image;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, event.toString());
if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
{
Log.d(TAG, "Caught a Toast: ");
Log.d(TAG, (String)event.getPackageName());
String toast = (String)event.getText().get(0);
Log.d(TAG, toast);
updateNotification(toast);
}
else
{
Log.d(TAG, "Caution! This service had been tampered with!");
}
}
@Override
public void onInterrupt() {
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
layouts = getSharedPreferences("layouts", 0);
}
}
@@ -0,0 +1,148 @@
package space.neothefox.laytray;
import android.content.SharedPreferences;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.util.Log;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity
implements View.OnClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
LinearLayout layoutLister;
SharedPreferences layouts;
public String TAG = "layiconActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layoutLister = findViewById(R.id.scrollLinearLayout);
layouts = getSharedPreferences("layouts", 0);
updateLayouts();
FloatingActionButton addButton = findViewById(R.id.floatingActionButton);
Button saveButton = findViewById(R.id.saveButton);
addButton.setOnClickListener(this);
saveButton.setOnClickListener(this);
}
protected void updateLayouts()
{
layoutLister.removeAllViewsInLayout();
Log.d(TAG, "Updateing Layouts:");
Map<String,?> keys = layouts.getAll();
if(keys != null)
{
Log.d(TAG, "listing map:");
int i = 0;
for(Map.Entry<String,?> entry : keys.entrySet()){
Log.d("map values",entry.getKey() + ": " +
entry.getValue().toString());
i++;
addLine(layoutLister, entry.getKey(), entry.getValue().toString());
}
if(i == 0)
{
populateLayouts();
}
}
else
{
populateLayouts();
}
}
protected void populateLayouts()
{
Log.d("map values", "Shared Prefs are empty");
SharedPreferences.Editor layoutsEditor = layouts.edit();
layoutsEditor.clear();
layoutsEditor.putString("Русский", "RU");
layoutsEditor.putString("Буквы (АБВ)", "EN");
layoutsEditor.commit();
}
protected void addLine(LinearLayout parent)
{
addLine(parent, "Name", "ICO");
}
protected void addLine(LinearLayout parent, String name, String icon)
{
LinearLayout layoutLine = new LinearLayout(getApplicationContext());
layoutLine.setOrientation(LinearLayout.HORIZONTAL);
EditText layoutName = new EditText(getApplicationContext());
layoutName.setText(name);
layoutLine.addView(layoutName);
EditText layoutIcon = new EditText(getApplicationContext());
layoutIcon.setText(icon);
layoutLine.addView(layoutIcon);
parent.addView(layoutLine);
}
protected void saveLayouts(LinearLayout parent)
{
int count = parent.getChildCount();
Log.d(TAG, String.format("%d layouts to save", count));
if (count != 0)
{
SharedPreferences.Editor layoutsEditor = layouts.edit();
layoutsEditor.clear();
for (int i=0; i < count; i++)
{
LinearLayout layoutLine = (LinearLayout)parent.getChildAt(i);
EditText layoutName = (EditText)layoutLine.getChildAt(0);
EditText layoutIcon = (EditText)layoutLine.getChildAt(1);
String layoutNameValue = layoutName.getText().toString();
String layoutIconValue = layoutIcon.getText().toString();
if(layoutNameValue != "")
{
if(layoutIconValue != "")
{
layoutsEditor.putString(layoutNameValue, layoutIconValue);
}
else
{
layoutsEditor.putString(layoutNameValue, "??");
}
}
}
layoutsEditor.commit();
}
}
@Override
public void onClick(View v) {
switch(v.getId())
{
case R.id.floatingActionButton:
addLine(layoutLister);
break;
case R.id.saveButton:
saveLayouts(layoutLister);
break;
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
layouts = getSharedPreferences("layouts", 0);
updateLayouts();
}
}
@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>
+69
View File
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="250dp"
android:layout_height="33dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="@string/activity_info"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:id="@+id/scrollView"
android:layout_width="368dp"
android:layout_height="407dp"
android:layout_marginBottom="32dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView">
<LinearLayout
android:id="@+id/scrollLinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="70dp"
android:layout_height="54dp"
android:layout_marginBottom="24dp"
android:layout_marginEnd="24dp"
android:clickable="true"
app:backgroundTint="?attr/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_input_add" />
<Button
android:id="@+id/saveButton"
android:layout_width="81dp"
android:layout_height="41dp"
android:layout_marginEnd="8dp"
android:text="Save"
app:layout_constraintEnd_toEndOf="parent"
tools:layout_editor_absoluteY="16dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:text="by NeoTheFox"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#002B36</color>
</resources>
+6
View File
@@ -0,0 +1,6 @@
<resources>
<string name="app_name">LayTray</string>
<string name="service_description">A simple layout icon</string>
<string name="accessibility_summary">LayTray needs to be enabled as an accessibility app, because the only way to get layout info on Android is by monitoring the Toast notification. Right now it monitors Blackberry Keyboard exclusively.</string>
<string name="activity_info">Associate layout name with layout icon</string>
</resources>
+11
View File
@@ -0,0 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>