1cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown/* 2cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * Copyright (C) 2012 The Android Open Source Project 3cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * 4cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * you may not use this file except in compliance with the License. 6cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * You may obtain a copy of the License at 7cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * 8cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * 10cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * Unless required by applicable law or agreed to in writing, software 11cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * See the License for the specific language governing permissions and 14cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * limitations under the License. 15cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown */ 16cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 17cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownpackage com.android.server.input; 18cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 19d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wrightimport com.android.internal.inputmethod.InputMethodSubtypeHandle; 20cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport com.android.internal.util.ArrayUtils; 21cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport com.android.internal.util.FastXmlSerializer; 22cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport com.android.internal.util.XmlUtils; 23cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 24cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport org.xmlpull.v1.XmlPullParser; 25cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport org.xmlpull.v1.XmlPullParserException; 26cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport org.xmlpull.v1.XmlSerializer; 27cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 28abb12ed4f2fe5843d5f23a1b3d29ade4f9da76e0Keisuke Kuroyanagiimport android.annotation.Nullable; 29d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gereckeimport android.view.Surface; 30d6396d67201fb2b64d13070324bb115c9c23b08aJason Gereckeimport android.hardware.input.TouchCalibration; 31d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wrightimport android.text.TextUtils; 32d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wrightimport android.util.ArrayMap; 3339606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile; 34cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport android.util.Slog; 35cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport android.util.Xml; 36cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 37cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.BufferedInputStream; 38cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.BufferedOutputStream; 39cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.File; 40cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.FileNotFoundException; 41cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.FileOutputStream; 42cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.IOException; 43cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.io.InputStream; 44d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wrightimport java.io.PrintWriter; 459e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewiczimport java.nio.charset.StandardCharsets; 46cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.util.ArrayList; 47d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wrightimport java.util.Arrays; 48cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.util.Collections; 49cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.util.HashMap; 50d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wrightimport java.util.List; 51cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.util.Map; 52cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport java.util.Set; 53cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 54cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport libcore.io.IoUtils; 55cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownimport libcore.util.Objects; 56cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 57cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown/** 58cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * Manages persistent state recorded by the input manager service as an XML file. 59cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * Caller must acquire lock on the data store before accessing it. 60cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * 61cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * File format: 62cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * <code> 63cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * <input-mananger-state> 64cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * <input-devices> 65cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * <input-device descriptor="xxxxx" keyboard-layout="yyyyy" /> 66cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * >input-devices> 67cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * >/input-manager-state> 68cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown * </code> 69cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown */ 70cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brownfinal class PersistentDataStore { 71cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown static final String TAG = "InputManager"; 72cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 73cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown // Input device state by descriptor. 74cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private final HashMap<String, InputDeviceState> mInputDevices = 75cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown new HashMap<String, InputDeviceState>(); 76cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private final AtomicFile mAtomicFile; 77cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 78cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown // True if the data has been loaded. 79cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private boolean mLoaded; 80cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 81cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown // True if there are changes to be saved. 82cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private boolean mDirty; 83cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 84cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public PersistentDataStore() { 85cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml")); 86cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 87cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 88cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public void saveIfNeeded() { 89cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (mDirty) { 90cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown save(); 91cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mDirty = false; 92cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 93cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 94cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 95d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke public TouchCalibration getTouchCalibration(String inputDeviceDescriptor, int surfaceRotation) { 96d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); 97d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke if (state == null) { 98d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke return TouchCalibration.IDENTITY; 99d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 100d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 101d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke TouchCalibration cal = state.getTouchCalibration(surfaceRotation); 102d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (cal == null) { 103d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return TouchCalibration.IDENTITY; 104d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 105d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return cal; 106d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 107d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke 108d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke public boolean setTouchCalibration(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration) { 109d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); 110d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 111d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (state.setTouchCalibration(surfaceRotation, calibration)) { 112d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke setDirty(); 113d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke return true; 114d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 115d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 116d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke return false; 117d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 118d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke 119cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public String getCurrentKeyboardLayout(String inputDeviceDescriptor) { 120cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); 121cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return state != null ? state.getCurrentKeyboardLayout() : null; 122cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 123cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 124cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean setCurrentKeyboardLayout(String inputDeviceDescriptor, 125cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown String keyboardLayoutDescriptor) { 126cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); 127cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (state.setCurrentKeyboardLayout(keyboardLayoutDescriptor)) { 128cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown setDirty(); 129cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 130cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 131cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 132cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 133cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 134cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public String[] getKeyboardLayouts(String inputDeviceDescriptor) { 135cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); 136cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (state == null) { 137cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return (String[])ArrayUtils.emptyArray(String.class); 138cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 139cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return state.getKeyboardLayouts(); 140cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 141d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public String getKeyboardLayout(String inputDeviceDescriptor, 142d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright InputMethodSubtypeHandle imeHandle) { 143d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); 144d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (state == null) { 145d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return null; 146d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 147d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return state.getKeyboardLayout(imeHandle); 148d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 149cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 150d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public boolean setKeyboardLayout(String inputDeviceDescriptor, 151d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) { 152d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); 153d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) { 154d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright setDirty(); 155d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return true; 156d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 157d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return false; 158d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 159d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 160d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) { 161cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); 162cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (state.addKeyboardLayout(keyboardLayoutDescriptor)) { 163cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown setDirty(); 164cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 165cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 166cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 167cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 168cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 169cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean removeKeyboardLayout(String inputDeviceDescriptor, 170cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown String keyboardLayoutDescriptor) { 171cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); 172cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (state.removeKeyboardLayout(keyboardLayoutDescriptor)) { 173cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown setDirty(); 174cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 175cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 176cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 177cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 178cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 179d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public boolean switchKeyboardLayout(String inputDeviceDescriptor, 180d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright InputMethodSubtypeHandle imeHandle) { 181cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); 182d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (state != null && state.switchKeyboardLayout(imeHandle)) { 183cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown setDirty(); 184cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 185cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 186cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 187cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 188cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 189cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) { 190cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown boolean changed = false; 191cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown for (InputDeviceState state : mInputDevices.values()) { 192cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (state.removeUninstalledKeyboardLayouts(availableKeyboardLayouts)) { 193cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown changed = true; 194cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 195cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 196cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (changed) { 197cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown setDirty(); 198cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 199cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 200cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 201cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 202cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 203cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private InputDeviceState getInputDeviceState(String inputDeviceDescriptor, 204cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown boolean createIfAbsent) { 205cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown loadIfNeeded(); 206cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = mInputDevices.get(inputDeviceDescriptor); 207cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (state == null && createIfAbsent) { 208cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown state = new InputDeviceState(); 209cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mInputDevices.put(inputDeviceDescriptor, state); 210cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown setDirty(); 211cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 212cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return state; 213cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 214cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 215cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void loadIfNeeded() { 216cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (!mLoaded) { 217cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown load(); 218cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mLoaded = true; 219cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 220cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 221cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 222cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void setDirty() { 223cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mDirty = true; 224cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 225cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 226cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void clearState() { 227cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mInputDevices.clear(); 228cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 229cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 230cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void load() { 231cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown clearState(); 232cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 233cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final InputStream is; 234cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown try { 235cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown is = mAtomicFile.openRead(); 236cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } catch (FileNotFoundException ex) { 237cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return; 238cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 239cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 240cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown XmlPullParser parser; 241cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown try { 242cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown parser = Xml.newPullParser(); 2439e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz parser.setInput(new BufferedInputStream(is), StandardCharsets.UTF_8.name()); 244cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown loadFromXml(parser); 245cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } catch (IOException ex) { 246cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown Slog.w(InputManagerService.TAG, "Failed to load input manager persistent store data.", ex); 247cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown clearState(); 248cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } catch (XmlPullParserException ex) { 249cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown Slog.w(InputManagerService.TAG, "Failed to load input manager persistent store data.", ex); 250cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown clearState(); 251cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } finally { 252cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown IoUtils.closeQuietly(is); 253cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 254cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 255cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 256cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void save() { 257cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final FileOutputStream os; 258cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown try { 259cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown os = mAtomicFile.startWrite(); 260cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown boolean success = false; 261cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown try { 262cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown XmlSerializer serializer = new FastXmlSerializer(); 2639e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz serializer.setOutput(new BufferedOutputStream(os), StandardCharsets.UTF_8.name()); 264cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown saveToXml(serializer); 265cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.flush(); 266cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown success = true; 267cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } finally { 268cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (success) { 269cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mAtomicFile.finishWrite(os); 270cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } else { 271cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mAtomicFile.failWrite(os); 272cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 273cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 274cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } catch (IOException ex) { 275cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown Slog.w(InputManagerService.TAG, "Failed to save input manager persistent store data.", ex); 276cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 277cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 278cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 279cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void loadFromXml(XmlPullParser parser) 280cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throws IOException, XmlPullParserException { 281cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown XmlUtils.beginDocument(parser, "input-manager-state"); 282cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final int outerDepth = parser.getDepth(); 283cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown while (XmlUtils.nextElementWithin(parser, outerDepth)) { 284cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (parser.getName().equals("input-devices")) { 285cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown loadInputDevicesFromXml(parser); 286cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 287cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 288cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 289cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 290cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void loadInputDevicesFromXml(XmlPullParser parser) 291cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throws IOException, XmlPullParserException { 292cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final int outerDepth = parser.getDepth(); 293cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown while (XmlUtils.nextElementWithin(parser, outerDepth)) { 294cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (parser.getName().equals("input-device")) { 295cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown String descriptor = parser.getAttributeValue(null, "descriptor"); 296cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (descriptor == null) { 297cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throw new XmlPullParserException( 298cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown "Missing descriptor attribute on input-device."); 299cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 300cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (mInputDevices.containsKey(descriptor)) { 301cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throw new XmlPullParserException("Found duplicate input device."); 302cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 303cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 304cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown InputDeviceState state = new InputDeviceState(); 305cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown state.loadFromXml(parser); 306cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mInputDevices.put(descriptor, state); 307cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 308cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 309cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 310cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 311cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void saveToXml(XmlSerializer serializer) throws IOException { 312cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.startDocument(null, true); 313cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 314cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.startTag(null, "input-manager-state"); 315cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.startTag(null, "input-devices"); 316cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) { 317cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final String descriptor = entry.getKey(); 318cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final InputDeviceState state = entry.getValue(); 319cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.startTag(null, "input-device"); 320cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.attribute(null, "descriptor", descriptor); 321cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown state.saveToXml(serializer); 322cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.endTag(null, "input-device"); 323cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 324cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.endTag(null, "input-devices"); 325cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.endTag(null, "input-manager-state"); 326cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.endDocument(); 327cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 328cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 329d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public void dump(PrintWriter pw, String prefix) { 330d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + "PersistentDataStore"); 331d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + " mLoaded=" + mLoaded); 332d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + " mDirty=" + mDirty); 333d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + " InputDeviceStates:"); 334d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright int i = 0; 335d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) { 336d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + " " + i++ + ": " + entry.getKey()); 337d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright entry.getValue().dump(pw, prefix + " "); 338d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 339d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 340d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 341cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private static final class InputDeviceState { 342d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke private static final String[] CALIBRATION_NAME = { "x_scale", 343d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke "x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" }; 344d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke 345d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke private TouchCalibration[] mTouchCalibration = new TouchCalibration[4]; 346abb12ed4f2fe5843d5f23a1b3d29ade4f9da76e0Keisuke Kuroyanagi @Nullable 347cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private String mCurrentKeyboardLayout; 348d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright private List<String> mUnassociatedKeyboardLayouts = new ArrayList<>(); 349d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright private ArrayMap<InputMethodSubtypeHandle, String> mKeyboardLayouts = new ArrayMap<>(); 350cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 351d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke public TouchCalibration getTouchCalibration(int surfaceRotation) { 352d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke try { 353d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return mTouchCalibration[surfaceRotation]; 354d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } catch (ArrayIndexOutOfBoundsException ex) { 355d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke Slog.w(InputManagerService.TAG, "Cannot get touch calibration.", ex); 356d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return null; 357d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 358d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 359d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke 360d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke public boolean setTouchCalibration(int surfaceRotation, TouchCalibration calibration) { 361d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke try { 362d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (!calibration.equals(mTouchCalibration[surfaceRotation])) { 363d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke mTouchCalibration[surfaceRotation] = calibration; 364d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return true; 365d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 366d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return false; 367d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } catch (ArrayIndexOutOfBoundsException ex) { 368d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke Slog.w(InputManagerService.TAG, "Cannot set touch calibration.", ex); 369d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke return false; 370d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 371d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 372d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke 373abb12ed4f2fe5843d5f23a1b3d29ade4f9da76e0Keisuke Kuroyanagi @Nullable 374cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public String getCurrentKeyboardLayout() { 375cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return mCurrentKeyboardLayout; 376cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 377cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 378cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean setCurrentKeyboardLayout(String keyboardLayout) { 379cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (Objects.equal(mCurrentKeyboardLayout, keyboardLayout)) { 380cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 381cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 382cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown addKeyboardLayout(keyboardLayout); 383cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mCurrentKeyboardLayout = keyboardLayout; 384cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 385cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 386cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 387cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public String[] getKeyboardLayouts() { 388d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (mUnassociatedKeyboardLayouts.isEmpty()) { 389cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return (String[])ArrayUtils.emptyArray(String.class); 390cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 391d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return mUnassociatedKeyboardLayouts.toArray( 392d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright new String[mUnassociatedKeyboardLayouts.size()]); 393d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 394d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 395d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public String getKeyboardLayout(InputMethodSubtypeHandle handle) { 396d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return mKeyboardLayouts.get(handle); 397d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 398d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 399d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle, 400d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright String keyboardLayout) { 401d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright String existingLayout = mKeyboardLayouts.get(imeHandle); 402d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (TextUtils.equals(existingLayout, keyboardLayout)) { 403d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return false; 404d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 405d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mKeyboardLayouts.put(imeHandle, keyboardLayout); 406d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return true; 407cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 408cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 409cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean addKeyboardLayout(String keyboardLayout) { 410d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright int index = Collections.binarySearch( 411d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mUnassociatedKeyboardLayouts, keyboardLayout); 412cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (index >= 0) { 413cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 414cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 415d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout); 416cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (mCurrentKeyboardLayout == null) { 417cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mCurrentKeyboardLayout = keyboardLayout; 418cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 419cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 420cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 421cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 422cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean removeKeyboardLayout(String keyboardLayout) { 423d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout); 424cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (index < 0) { 425cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return false; 426cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 427d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mUnassociatedKeyboardLayouts.remove(index); 428cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index); 429cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return true; 430cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 431cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 432cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown private void updateCurrentKeyboardLayoutIfRemoved( 433cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown String removedKeyboardLayout, int removedIndex) { 434cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (Objects.equal(mCurrentKeyboardLayout, removedKeyboardLayout)) { 435d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (!mUnassociatedKeyboardLayouts.isEmpty()) { 436cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown int index = removedIndex; 437d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (index == mUnassociatedKeyboardLayouts.size()) { 438cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown index = 0; 439cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 440d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index); 441cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } else { 442cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mCurrentKeyboardLayout = null; 443cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 444cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 445cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 446cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 447d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) { 448d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright final String layout = mKeyboardLayouts.get(imeHandle); 449abb12ed4f2fe5843d5f23a1b3d29ade4f9da76e0Keisuke Kuroyanagi if (!TextUtils.equals(mCurrentKeyboardLayout, layout)) { 450d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mCurrentKeyboardLayout = layout; 451d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return true; 452cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 453d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright return false; 454cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 455cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 456cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) { 457cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown boolean changed = false; 458d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) { 459d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright String keyboardLayout = mUnassociatedKeyboardLayouts.get(i); 460cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (!availableKeyboardLayouts.contains(keyboardLayout)) { 461cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout); 462d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mUnassociatedKeyboardLayouts.remove(i); 463cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i); 464cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown changed = true; 465cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 466cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 467cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown return changed; 468cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 469cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 470cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public void loadFromXml(XmlPullParser parser) 471cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throws IOException, XmlPullParserException { 472cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown final int outerDepth = parser.getDepth(); 473cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown while (XmlUtils.nextElementWithin(parser, outerDepth)) { 474cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (parser.getName().equals("keyboard-layout")) { 475cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown String descriptor = parser.getAttributeValue(null, "descriptor"); 476cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (descriptor == null) { 477cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throw new XmlPullParserException( 478cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown "Missing descriptor attribute on keyboard-layout."); 479cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 480cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 481d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright String current = parser.getAttributeValue(null, "current"); 482cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (current != null && current.equals("true")) { 483cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (mCurrentKeyboardLayout != null) { 484cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown throw new XmlPullParserException( 485cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown "Found multiple current keyboard layouts."); 486cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 487cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown mCurrentKeyboardLayout = descriptor; 488cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 489d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 490d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright String inputMethodId = parser.getAttributeValue(null, "input-method-id"); 491d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright String inputMethodSubtypeId = 492d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright parser.getAttributeValue(null, "input-method-subtype-id"); 493d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (inputMethodId == null && inputMethodSubtypeId != null 494d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright || inputMethodId != null && inputMethodSubtypeId == null) { 495d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright throw new XmlPullParserException( 496d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright "Found an incomplete input method description"); 497d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 498d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 499d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (inputMethodSubtypeId != null) { 500d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle( 501d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright inputMethodId, Integer.parseInt(inputMethodSubtypeId)); 502d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (mKeyboardLayouts.containsKey(handle)) { 503d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright throw new XmlPullParserException( 504d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright "Found duplicate subtype to keyboard layout mapping: " 505d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright + handle); 506d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 507d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mKeyboardLayouts.put(handle, descriptor); 508d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } else { 509d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (mUnassociatedKeyboardLayouts.contains(descriptor)) { 510d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright throw new XmlPullParserException( 511d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright "Found duplicate unassociated keyboard layout: " + descriptor); 512d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 513d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mUnassociatedKeyboardLayouts.add(descriptor); 514d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 515d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } else if (parser.getName().equals("calibration")) { 516d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke String format = parser.getAttributeValue(null, "format"); 517d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke String rotation = parser.getAttributeValue(null, "rotation"); 518d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke int r = -1; 519d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 520d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke if (format == null) { 521d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke throw new XmlPullParserException( 522d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke "Missing format attribute on calibration."); 523d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 524d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (!format.equals("affine")) { 525d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke throw new XmlPullParserException( 526d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke "Unsupported format for calibration."); 527d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 528d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (rotation != null) { 529d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke try { 530d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke r = stringToSurfaceRotation(rotation); 531d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } catch (IllegalArgumentException e) { 532d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke throw new XmlPullParserException( 533d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke "Unsupported rotation for calibration."); 534d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 535d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 536d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 537d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke float[] matrix = TouchCalibration.IDENTITY.getAffineTransform(); 538d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke int depth = parser.getDepth(); 539d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke while (XmlUtils.nextElementWithin(parser, depth)) { 540d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke String tag = parser.getName().toLowerCase(); 541d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke String value = parser.nextText(); 542d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 543d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke for (int i = 0; i < matrix.length && i < CALIBRATION_NAME.length; i++) { 544d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (tag.equals(CALIBRATION_NAME[i])) { 545d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke matrix[i] = Float.parseFloat(value); 546d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke break; 547d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 548d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 549d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 550d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 551d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (r == -1) { 552d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke // Assume calibration applies to all rotations 553d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke for (r = 0; r < mTouchCalibration.length; r++) { 554d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke mTouchCalibration[r] = new TouchCalibration(matrix[0], 555d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); 556d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 557d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } else { 558d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke mTouchCalibration[r] = new TouchCalibration(matrix[0], 559d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); 560d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 561cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 562cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 563cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 564cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown // Maintain invariant that layouts are sorted. 565d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright Collections.sort(mUnassociatedKeyboardLayouts); 566cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 567cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown // Maintain invariant that there is always a current keyboard layout unless 568cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown // there are none installed. 569d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) { 570d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0); 571cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 572cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 573cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown 574cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown public void saveToXml(XmlSerializer serializer) throws IOException { 575d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright for (String layout : mUnassociatedKeyboardLayouts) { 576d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright serializer.startTag(null, "keyboard-layout"); 577d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright serializer.attribute(null, "descriptor", layout); 578d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright serializer.endTag(null, "keyboard-layout"); 579d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 580d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 581d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright final int N = mKeyboardLayouts.size(); 582d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright for (int i = 0; i < N; i++) { 583d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i); 584d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright final String layout = mKeyboardLayouts.valueAt(i); 585cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.startTag(null, "keyboard-layout"); 586cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.attribute(null, "descriptor", layout); 587d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright serializer.attribute(null, "input-method-id", handle.getInputMethodId()); 588d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright serializer.attribute(null, "input-method-subtype-id", 589d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright Integer.toString(handle.getSubtypeId())); 590cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown if (layout.equals(mCurrentKeyboardLayout)) { 591cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.attribute(null, "current", "true"); 592cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 593cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown serializer.endTag(null, "keyboard-layout"); 594cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 595d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke 596d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke for (int i = 0; i < mTouchCalibration.length; i++) { 597d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if (mTouchCalibration[i] != null) { 598d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke String rotation = surfaceRotationToString(i); 599d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke float[] transform = mTouchCalibration[i].getAffineTransform(); 600d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 601d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.startTag(null, "calibration"); 602d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.attribute(null, "format", "affine"); 603d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.attribute(null, "rotation", rotation); 604d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke for (int j = 0; j < transform.length && j < CALIBRATION_NAME.length; j++) { 605d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.startTag(null, CALIBRATION_NAME[j]); 606d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.text(Float.toString(transform[j])); 607d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.endTag(null, CALIBRATION_NAME[j]); 608d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 609d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke serializer.endTag(null, "calibration"); 610d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 611d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 612d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 613d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright 614d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright private void dump(final PrintWriter pw, final String prefix) { 615d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout); 616d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts); 617d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration)); 618d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + "Subtype to Layout Mappings:"); 619d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright final int N = mKeyboardLayouts.size(); 620d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright if (N != 0) { 621d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright for (int i = 0; i < N; i++) { 622d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + " " + mKeyboardLayouts.keyAt(i) + ": " 623d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright + mKeyboardLayouts.valueAt(i)); 624d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 625d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } else { 626d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright pw.println(prefix + " <none>"); 627d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 628d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907Michael Wright } 629d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 630d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke private static String surfaceRotationToString(int surfaceRotation) { 631d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke switch (surfaceRotation) { 632d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke case Surface.ROTATION_0: return "0"; 633d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke case Surface.ROTATION_90: return "90"; 634d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke case Surface.ROTATION_180: return "180"; 635d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke case Surface.ROTATION_270: return "270"; 636d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 637d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke throw new IllegalArgumentException("Unsupported surface rotation value" + surfaceRotation); 638d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 639d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke 640d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke private static int stringToSurfaceRotation(String s) { 641d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if ("0".equals(s)) { 642d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return Surface.ROTATION_0; 643d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 644d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if ("90".equals(s)) { 645d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return Surface.ROTATION_90; 646d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 647d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if ("180".equals(s)) { 648d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return Surface.ROTATION_180; 649d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke } 650d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke if ("270".equals(s)) { 651d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke return Surface.ROTATION_270; 652d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke } 653d52207423225bcd99e94276e9d0fc2cb5f905602Jason Gerecke throw new IllegalArgumentException("Unsupported surface rotation string '" + s + "'"); 654cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 655cf39bdf3dff5e29447f6ce734b76dc3490385e58Jeff Brown } 656d6396d67201fb2b64d13070324bb115c9c23b08aJason Gerecke} 657