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