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