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

Commit b1ab4249 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari Committed by Android (Google) Code Review
Browse files

Merge "Add keyboard backlight controller"

parents c65a42f8 d0947e73
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -140,4 +140,16 @@ public abstract class InputManagerInternal {
     * canceled for all other channels.
     */
    public abstract void pilferPointers(IBinder token);

    /**
     * Increments keyboard backlight level if the device has an associated keyboard backlight
     * {@see Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT}
     */
    public abstract void incrementKeyboardBacklight(int deviceId);

    /**
     * Decrements keyboard backlight level if the device has an associated keyboard backlight
     * {@see Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT}
     */
    public abstract void decrementKeyboardBacklight(int deviceId);
}
+17 −0
Original line number Diff line number Diff line
@@ -312,6 +312,9 @@ public class InputManagerService extends IInputManager.Stub
    // Manages battery state for input devices.
    private final BatteryController mBatteryController;

    // Manages Keyboard backlight
    private final KeyboardBacklightController mKeyboardBacklightController;

    // Maximum number of milliseconds to wait for input event injection.
    private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;

@@ -422,6 +425,8 @@ public class InputManagerService extends IInputManager.Stub
        mHandler = new InputManagerHandler(injector.getLooper());
        mNative = injector.getNativeService(this);
        mBatteryController = new BatteryController(mContext, mNative, injector.getLooper());
        mKeyboardBacklightController = new KeyboardBacklightController(mContext, mNative,
                mDataStore, injector.getLooper());

        mUseDevInputEventForAudioJack =
                mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
@@ -563,6 +568,7 @@ public class InputManagerService extends IInputManager.Stub
        }

        mBatteryController.systemRunning();
        mKeyboardBacklightController.systemRunning();
    }

    private void reloadKeyboardLayouts() {
@@ -2680,6 +2686,7 @@ public class InputManagerService extends IInputManager.Stub
        dumpSpyWindowGestureMonitors(pw, "  " /*prefix*/);
        dumpDisplayInputPropertiesValues(pw, "  " /*prefix*/);
        mBatteryController.dump(pw, "  " /*prefix*/);
        mKeyboardBacklightController.dump(pw, "  " /*prefix*/);
    }

    private void dumpAssociations(PrintWriter pw, String prefix) {
@@ -3757,6 +3764,16 @@ public class InputManagerService extends IInputManager.Stub
        public void pilferPointers(IBinder token) {
            mNative.pilferPointers(token);
        }

        @Override
        public void incrementKeyboardBacklight(int deviceId) {
            mKeyboardBacklightController.incrementKeyboardBacklight(deviceId);
        }

        @Override
        public void decrementKeyboardBacklight(int deviceId) {
            mKeyboardBacklightController.decrementKeyboardBacklight(deviceId);
        }
    }

    @Override
+227 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.server.input;

import android.annotation.ColorInt;
import android.content.Context;
import android.graphics.Color;
import android.hardware.input.InputManager;
import android.hardware.lights.Light;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.InputDevice;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.TreeSet;

/**
 * A thread-safe component of {@link InputManagerService} responsible for managing the keyboard
 * backlight for supported keyboards.
 */
final class KeyboardBacklightController implements InputManager.InputDeviceListener {

    private static final String TAG = "KbdBacklightController";

    // To enable these logs, run:
    // 'adb shell setprop log.tag.KbdBacklightController DEBUG' (requires restart)
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private enum Direction {
        DIRECTION_UP, DIRECTION_DOWN
    }
    private static final int MSG_INCREMENT_KEYBOARD_BACKLIGHT = 1;
    private static final int MSG_DECREMENT_KEYBOARD_BACKLIGHT = 2;
    private static final int MAX_BRIGHTNESS = 255;
    private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10;
    @VisibleForTesting
    static final TreeSet<Integer> BRIGHTNESS_LEVELS = new TreeSet<>();

    private final Context mContext;
    private final NativeInputManagerService mNative;
    // The PersistentDataStore should be locked before use.
    @GuardedBy("mDataStore")
    private final PersistentDataStore mDataStore;
    private final Handler mHandler;
    private final SparseArray<Light> mKeyboardBacklights = new SparseArray<>();

    static {
        // Fixed brightness levels to avoid issues when converting back and forth from the
        // device brightness range to [0-255]
        // Levels are: 0, 25, 51, ..., 255
        for (int i = 0; i <= NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
            BRIGHTNESS_LEVELS.add(
                    (int) Math.floor(((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS));
        }
    }

    KeyboardBacklightController(Context context, NativeInputManagerService nativeService,
            PersistentDataStore dataStore, Looper looper) {
        mContext = context;
        mNative = nativeService;
        mDataStore = dataStore;
        mHandler = new Handler(looper, this::handleMessage);
    }

    void systemRunning() {
        InputManager inputManager = Objects.requireNonNull(
                mContext.getSystemService(InputManager.class));
        inputManager.registerInputDeviceListener(this, mHandler);
        // Circle through all the already added input devices
        for (int deviceId : inputManager.getInputDeviceIds()) {
            onInputDeviceAdded(deviceId);
        }
    }

    public void incrementKeyboardBacklight(int deviceId) {
        Message msg = Message.obtain(mHandler, MSG_INCREMENT_KEYBOARD_BACKLIGHT, deviceId);
        mHandler.sendMessage(msg);
    }

    public void decrementKeyboardBacklight(int deviceId) {
        Message msg = Message.obtain(mHandler, MSG_DECREMENT_KEYBOARD_BACKLIGHT, deviceId);
        mHandler.sendMessage(msg);
    }

    private void updateKeyboardBacklight(int deviceId, Direction direction) {
        InputDevice inputDevice = getInputDevice(deviceId);
        Light keyboardBacklight = mKeyboardBacklights.get(deviceId);
        if (inputDevice == null || keyboardBacklight == null) {
            return;
        }
        // Follow preset levels of brightness defined in BRIGHTNESS_LEVELS
        int currBrightness = BRIGHTNESS_LEVELS.floor(Color.alpha(
                mNative.getLightColor(deviceId, keyboardBacklight.getId())));
        int newBrightness;
        if (direction == Direction.DIRECTION_UP) {
            newBrightness = currBrightness != MAX_BRIGHTNESS ? BRIGHTNESS_LEVELS.higher(
                    currBrightness) : currBrightness;
        } else {
            newBrightness = currBrightness != 0 ? BRIGHTNESS_LEVELS.lower(currBrightness)
                    : currBrightness;
        }
        @ColorInt int newColor = Color.argb(newBrightness, 0, 0, 0);
        mNative.setLightColor(deviceId, keyboardBacklight.getId(), newColor);
        if (DEBUG) {
            Slog.d(TAG, "Changing brightness from " + currBrightness + " to " + newBrightness);
        }

        synchronized (mDataStore) {
            try {
                mDataStore.setKeyboardBacklightBrightness(inputDevice.getDescriptor(),
                        keyboardBacklight.getId(),
                        newBrightness);
            } finally {
                mDataStore.saveIfNeeded();
            }
        }
    }

    private void restoreBacklightBrightness(InputDevice inputDevice, Light keyboardBacklight) {
        OptionalInt brightness;
        synchronized (mDataStore) {
            brightness = mDataStore.getKeyboardBacklightBrightness(
                    inputDevice.getDescriptor(), keyboardBacklight.getId());
        }
        if (!brightness.isEmpty()) {
            mNative.setLightColor(inputDevice.getId(), keyboardBacklight.getId(),
                    Color.argb(brightness.getAsInt(), 0, 0, 0));
            if (DEBUG) {
                Slog.d(TAG, "Restoring brightness level " + brightness.getAsInt());
            }
        }
    }

    private boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_INCREMENT_KEYBOARD_BACKLIGHT:
                updateKeyboardBacklight((int) msg.obj, Direction.DIRECTION_UP);
                return true;
            case MSG_DECREMENT_KEYBOARD_BACKLIGHT:
                updateKeyboardBacklight((int) msg.obj, Direction.DIRECTION_DOWN);
                return true;
        }
        return false;
    }

    @VisibleForTesting
    @Override
    public void onInputDeviceAdded(int deviceId) {
        onInputDeviceChanged(deviceId);
    }

    @VisibleForTesting
    @Override
    public void onInputDeviceRemoved(int deviceId) {
        mKeyboardBacklights.remove(deviceId);
    }

    @VisibleForTesting
    @Override
    public void onInputDeviceChanged(int deviceId) {
        InputDevice inputDevice = getInputDevice(deviceId);
        if (inputDevice == null) {
            return;
        }
        final Light keyboardBacklight = getKeyboardBacklight(inputDevice);
        if (keyboardBacklight == null) {
            mKeyboardBacklights.remove(deviceId);
            return;
        }
        final Light oldBacklight = mKeyboardBacklights.get(deviceId);
        if (oldBacklight != null && oldBacklight.getId() == keyboardBacklight.getId()) {
            return;
        }
        // The keyboard backlight was added or changed.
        mKeyboardBacklights.put(deviceId, keyboardBacklight);
        restoreBacklightBrightness(inputDevice, keyboardBacklight);
    }

    private InputDevice getInputDevice(int deviceId) {
        InputManager inputManager = mContext.getSystemService(InputManager.class);
        return inputManager != null ? inputManager.getInputDevice(deviceId) : null;
    }

    private Light getKeyboardBacklight(InputDevice inputDevice) {
        // Assuming each keyboard can have only single Light node for Keyboard backlight control
        // for simplicity.
        for (Light light : inputDevice.getLightsManager().getLights()) {
            if (light.getType() == Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT
                    && light.hasBrightnessControl()) {
                return light;
            }
        }
        return null;
    }

    void dump(PrintWriter pw, String prefix) {
        pw.println(prefix + TAG + ": " + mKeyboardBacklights.size() + " keyboard backlights");
        for (int i = 0; i < mKeyboardBacklights.size(); i++) {
            Light light = mKeyboardBacklights.get(i);
            pw.println(prefix + "  " + i + ": { id: " + light.getId() + ", name: " + light.getName()
                    + " }");
        }
    }
}
+112 −37
Original line number Diff line number Diff line
@@ -16,40 +16,37 @@

package com.android.server.input;

import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import android.annotation.Nullable;
import android.view.Surface;
import android.hardware.input.TouchCalibration;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Surface;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;

import libcore.io.IoUtils;

import org.xmlpull.v1.XmlPullParserException;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.Set;

import libcore.io.IoUtils;

/**
 * Manages persistent state recorded by the input manager service as an XML file.
 * Caller must acquire lock on the data store before accessing it.
@@ -69,7 +66,9 @@ final class PersistentDataStore {
    // Input device state by descriptor.
    private final HashMap<String, InputDeviceState> mInputDevices =
            new HashMap<String, InputDeviceState>();
    private final AtomicFile mAtomicFile;

    // The interface for methods which should be replaced by the test harness.
    private Injector mInjector;

    // True if the data has been loaded.
    private boolean mLoaded;
@@ -78,8 +77,12 @@ final class PersistentDataStore {
    private boolean mDirty;

    public PersistentDataStore() {
        mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"),
                "input-state");
        this(new Injector());
    }

    @VisibleForTesting
    PersistentDataStore(Injector injector) {
        mInjector = injector;
    }

    public void saveIfNeeded() {
@@ -90,7 +93,7 @@ final class PersistentDataStore {
    }

    public TouchCalibration getTouchCalibration(String inputDeviceDescriptor, int surfaceRotation) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        if (state == null) {
            return TouchCalibration.IDENTITY;
        }
@@ -103,7 +106,7 @@ final class PersistentDataStore {
    }

    public boolean setTouchCalibration(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
        InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);

        if (state.setTouchCalibration(surfaceRotation, calibration)) {
            setDirty();
@@ -114,13 +117,13 @@ final class PersistentDataStore {
    }

    public String getCurrentKeyboardLayout(String inputDeviceDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        return state != null ? state.getCurrentKeyboardLayout() : null;
    }

    public boolean setCurrentKeyboardLayout(String inputDeviceDescriptor,
            String keyboardLayoutDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
        InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
        if (state.setCurrentKeyboardLayout(keyboardLayoutDescriptor)) {
            setDirty();
            return true;
@@ -129,7 +132,7 @@ final class PersistentDataStore {
    }

    public String[] getKeyboardLayouts(String inputDeviceDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        if (state == null) {
            return (String[])ArrayUtils.emptyArray(String.class);
        }
@@ -138,7 +141,7 @@ final class PersistentDataStore {

    public boolean addKeyboardLayout(String inputDeviceDescriptor,
            String keyboardLayoutDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
        InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
        if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
            setDirty();
            return true;
@@ -148,7 +151,7 @@ final class PersistentDataStore {

    public boolean removeKeyboardLayout(String inputDeviceDescriptor,
            String keyboardLayoutDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
        InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
        if (state.removeKeyboardLayout(keyboardLayoutDescriptor)) {
            setDirty();
            return true;
@@ -157,7 +160,7 @@ final class PersistentDataStore {
    }

    public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        if (state != null && state.switchKeyboardLayout(direction)) {
            setDirty();
            return true;
@@ -165,6 +168,24 @@ final class PersistentDataStore {
        return false;
    }

    public boolean setKeyboardBacklightBrightness(String inputDeviceDescriptor, int lightId,
            int brightness) {
        InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
        if (state.setKeyboardBacklightBrightness(lightId, brightness)) {
            setDirty();
            return true;
        }
        return false;
    }

    public OptionalInt getKeyboardBacklightBrightness(String inputDeviceDescriptor, int lightId) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        if (state == null) {
            return OptionalInt.empty();
        }
        return state.getKeyboardBacklightBrightness(lightId);
    }

    public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
        boolean changed = false;
        for (InputDeviceState state : mInputDevices.values()) {
@@ -179,11 +200,15 @@ final class PersistentDataStore {
        return false;
    }

    private InputDeviceState getInputDeviceState(String inputDeviceDescriptor,
            boolean createIfAbsent) {
    private InputDeviceState getInputDeviceState(String inputDeviceDescriptor) {
        loadIfNeeded();
        return mInputDevices.get(inputDeviceDescriptor);
    }

    private InputDeviceState getOrCreateInputDeviceState(String inputDeviceDescriptor) {
        loadIfNeeded();
        InputDeviceState state = mInputDevices.get(inputDeviceDescriptor);
        if (state == null && createIfAbsent) {
        if (state == null) {
            state = new InputDeviceState();
            mInputDevices.put(inputDeviceDescriptor, state);
            setDirty();
@@ -211,7 +236,7 @@ final class PersistentDataStore {

        final InputStream is;
        try {
            is = mAtomicFile.openRead();
            is = mInjector.openRead();
        } catch (FileNotFoundException ex) {
            return;
        }
@@ -234,7 +259,7 @@ final class PersistentDataStore {
    private void save() {
        final FileOutputStream os;
        try {
            os = mAtomicFile.startWrite();
            os = mInjector.startWrite();
            boolean success = false;
            try {
                TypedXmlSerializer serializer = Xml.resolveSerializer(os);
@@ -242,11 +267,7 @@ final class PersistentDataStore {
                serializer.flush();
                success = true;
            } finally {
                if (success) {
                    mAtomicFile.finishWrite(os);
                } else {
                    mAtomicFile.failWrite(os);
                }
                mInjector.finishWrite(os, success);
            }
        } catch (IOException ex) {
            Slog.w(InputManagerService.TAG, "Failed to save input manager persistent store data.", ex);
@@ -307,10 +328,12 @@ final class PersistentDataStore {
        private static final String[] CALIBRATION_NAME = { "x_scale",
                "x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };

        private TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
        private static final int INVALID_VALUE = -1;
        private final TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
        @Nullable
        private String mCurrentKeyboardLayout;
        private ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
        private final ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
        private final SparseIntArray mKeyboardBacklightBrightnessMap = new SparseIntArray();

        public TouchCalibration getTouchCalibration(int surfaceRotation) {
            try {
@@ -377,6 +400,19 @@ final class PersistentDataStore {
            return true;
        }

        public boolean setKeyboardBacklightBrightness(int lightId, int brightness) {
            if (mKeyboardBacklightBrightnessMap.get(lightId, INVALID_VALUE) == brightness) {
                return false;
            }
            mKeyboardBacklightBrightnessMap.put(lightId, brightness);
            return true;
        }

        public OptionalInt getKeyboardBacklightBrightness(int lightId) {
            int brightness = mKeyboardBacklightBrightnessMap.get(lightId, INVALID_VALUE);
            return brightness == INVALID_VALUE ? OptionalInt.empty() : OptionalInt.of(brightness);
        }

        private void updateCurrentKeyboardLayoutIfRemoved(
                String removedKeyboardLayout, int removedIndex) {
            if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) {
@@ -446,6 +482,10 @@ final class PersistentDataStore {
                        }
                        mCurrentKeyboardLayout = descriptor;
                    }
                } else if (parser.getName().equals("light-info")) {
                    int lightId = parser.getAttributeInt(null, "light-id");
                    int lightBrightness = parser.getAttributeInt(null, "light-brightness");
                    mKeyboardBacklightBrightnessMap.put(lightId, lightBrightness);
                } else if (parser.getName().equals("calibration")) {
                    String format = parser.getAttributeValue(null, "format");
                    String rotation = parser.getAttributeValue(null, "rotation");
@@ -515,6 +555,15 @@ final class PersistentDataStore {
                serializer.endTag(null, "keyboard-layout");
            }

            for (int i = 0; i < mKeyboardBacklightBrightnessMap.size(); i++) {
                int lightId = mKeyboardBacklightBrightnessMap.valueAt(i);
                serializer.startTag(null, "light-info");
                serializer.attributeInt(null, "light-id", lightId);
                serializer.attributeInt(null, "light-brightness",
                        mKeyboardBacklightBrightnessMap.get(lightId));
                serializer.endTag(null, "light-info");
            }

            for (int i = 0; i < mTouchCalibration.length; i++) {
                if (mTouchCalibration[i] != null) {
                    String rotation = surfaceRotationToString(i);
@@ -559,4 +608,30 @@ final class PersistentDataStore {
            throw new IllegalArgumentException("Unsupported surface rotation string '" + s + "'");
        }
    }

    @VisibleForTesting
    static class Injector {
        private final AtomicFile mAtomicFile;

        Injector() {
            mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"),
                    "input-state");
        }

        InputStream openRead() throws FileNotFoundException {
            return mAtomicFile.openRead();
        }

        FileOutputStream startWrite() throws IOException {
            return mAtomicFile.startWrite();
        }

        void finishWrite(FileOutputStream fos, boolean success) {
            if (success) {
                mAtomicFile.finishWrite(fos);
            } else {
                mAtomicFile.failWrite(fos);
            }
        }
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -2931,9 +2931,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                }
                return key_consumed;
            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
                if (down) {
                    mInputManagerInternal.decrementKeyboardBacklight(event.getDeviceId());
                }
                return key_consumed;
            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
                if (down) {
                    mInputManagerInternal.incrementKeyboardBacklight(event.getDeviceId());
                }
                return key_consumed;
            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
                // TODO: Add logic to handle keyboard backlight controls (go/pk_backlight_control)
                // TODO: Add logic
                return key_consumed;
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_DOWN:
Loading