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

Commit 8457ad89 authored by Jason Monk's avatar Jason Monk
Browse files

Add keycode buttons to nav bar tuner

Allow a keycode (list generated from KeyEvent.java) and a image to
be selected as a new KeyButtonView to be shown in the nav bar.

Change-Id: I26fcad5b74a96090f2c5574fd214b4afbcadbb30
parent 3b587143
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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.
-->
<com.android.systemui.statusbar.policy.KeyButtonView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res-auto"
    android:layout_width="@dimen/navigation_side_padding"
    android:layout_height="match_parent"
    android:layout_weight="0"
    android:scaleType="center"
    android:tint="@android:color/white"
    android:contentDescription="@string/accessibility_key" />
+15 −0
Original line number Diff line number Diff line
@@ -1387,4 +1387,19 @@
    <!-- SysUI Tuner: Description of nav bar button that holds the clipboard [CHAR LIMIT=NONE] -->
    <string name="clipboard_description">The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present.</string>

    <!-- SysUI Tuner: Accessibility description for custom nav key [CHAR LIMIT=NONE] -->
    <string name="accessibility_key">Custom navigation button</string>

    <!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
    <string name="keycode">Keycode</string>

    <!-- SysUI Tuner: Description of nav bar button that emulates a keycode [CHAR LIMIT=NONE] -->
    <string name="keycode_description">Keycode buttons allow keyboard keys to
        be added to the Navigation Bar. When pressed they emulate the selected
        keyboard key. First the key must be selected for the button, followed
        by an image to be shown on the button.</string>

    <!-- SysUI Tuner: Title of dialog to select which key to emulate [CHAR LIMIT=60] -->
    <string name="select_keycode">Select Keyboard Button</string>

</resources>
+40 −3
Original line number Diff line number Diff line
@@ -18,7 +18,10 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -28,8 +31,10 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.tuner.TunerService;

import java.io.File;
import java.util.Objects;

public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
@@ -44,18 +49,24 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
    public static final String RECENT = "recent";
    public static final String NAVSPACE = "space";
    public static final String CLIPBOARD = "clipboard";
    public static final String KEY = "key";

    public static final String GRAVITY_SEPARATOR = ";";
    public static final String BUTTON_SEPARATOR = ",";

    protected final LayoutInflater mLayoutInflater;
    protected final LayoutInflater mLandscapeInflater;

    public static final String SIZE_MOD_START = "[";
    public static final String SIZE_MOD_END = "]";

    public static final String KEY_CODE_START = "(";
    public static final String KEY_IMAGE_DELIM = ":";
    public static final String KEY_CODE_END = ")";

    protected final LayoutInflater mLayoutInflater;
    protected final LayoutInflater mLandscapeInflater;

    protected FrameLayout mRot0;
    protected FrameLayout mRot90;

    private SparseArray<ButtonDispatcher> mButtonDispatchers;
    private String mCurrentLayout;

@@ -236,6 +247,14 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
            v = inflater.inflate(R.layout.nav_key_space, parent, false);
        } else if (CLIPBOARD.equals(button)) {
            v = inflater.inflate(R.layout.clipboard, parent, false);
        } else if (button.startsWith(KEY)) {
            String uri = extractImage(button);
            int code = extractKeycode(button);
            v = inflater.inflate(R.layout.custom_key, parent, false);
            ((KeyButtonView) v).setCode(code);
            if (uri != null) {
                ((KeyButtonView) v).loadAsync(uri);
            }
        } else {
            return null;
        }
@@ -249,6 +268,24 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
        return v;
    }

    public static String extractImage(String buttonSpec) {
        if (!buttonSpec.contains(KEY_IMAGE_DELIM)) {
            return null;
        }
        final int start = buttonSpec.indexOf(KEY_IMAGE_DELIM);
        String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_CODE_END));
        return subStr;
    }

    public static int extractKeycode(String buttonSpec) {
        if (!buttonSpec.contains(KEY_CODE_START)) {
            return 1;
        }
        final int start = buttonSpec.indexOf(KEY_CODE_START);
        String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_IMAGE_DELIM));
        return Integer.parseInt(subStr);
    }

    public static float extractSize(String buttonSpec) {
        if (!buttonSpec.contains(SIZE_MOD_START)) {
            return 1;
+22 −0
Original line number Diff line number Diff line
@@ -20,8 +20,12 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -99,6 +103,24 @@ public class KeyButtonView extends ImageView {
        setBackground(new KeyButtonRipple(context, this));
    }

    public void setCode(int code) {
        mCode = code;
    }

    public void loadAsync(String uri) {
        new AsyncTask<String, Void, Drawable>() {
            @Override
            protected Drawable doInBackground(String... params) {
                return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
            }

            @Override
            protected void onPostExecute(Drawable drawable) {
                setImageDrawable(drawable);
            }
        }.execute(uri);
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.systemui.tuner;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Pair;
import android.view.KeyEvent;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import com.android.systemui.R;

public class KeycodeSelectionHelper {

    private static final ArrayList<String> mKeycodeStrings = new ArrayList<>();
    private static final ArrayList<Integer> mKeycodes = new ArrayList<>();

    private static final String KEYCODE_STRING = "KEYCODE_";

    static {
        Class<KeyEvent> cls = KeyEvent.class;
        for (Field field : cls.getDeclaredFields()) {
            if (Modifier.isStatic(field.getModifiers())
                    && field.getName().startsWith(KEYCODE_STRING)
                    && field.getType().equals(int.class)) {
                try {
                    mKeycodeStrings.add(formatString(field.getName()));
                    mKeycodes.add((Integer) field.get(null));
                } catch (IllegalAccessException e) {
                }
            }
        }
    }

    // Force the string into something somewhat readable.
    private static String formatString(String name) {
        StringBuilder str = new StringBuilder(name.replace(KEYCODE_STRING, "").replace("_", " ")
                .toLowerCase());
        for (int i = 0; i < str.length(); i++) {
            if (i == 0 || str.charAt(i - 1) == ' ') {
                str.setCharAt(i, Character.toUpperCase(str.charAt(i)));
            }
        }
        return str.toString();
    }

    public static void showKeycodeSelect(Context context, final OnSelectionComplete listener) {
        new AlertDialog.Builder(context)
                .setTitle(R.string.select_keycode)
                .setItems(mKeycodeStrings.toArray(new String[0]),
                        new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        listener.onSelectionComplete(mKeycodes.get(which));
                    }
                }).show();
    }

    public static Intent getSelectImageIntent() {
        return new Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)
                .setType("image/*");
    }

    public interface OnSelectionComplete {
        void onSelectionComplete(int code);
    }
}
Loading