1eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad/* 2eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Copyright (C) 2016 The Android Open Source Project 3eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * 4eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Licensed under the Apache License, Version 2.0 (the "License"); 5eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * you may not use this file except in compliance with the License. 6eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * You may obtain a copy of the License at 7eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * 8eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * http://www.apache.org/licenses/LICENSE-2.0 9eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * 10eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Unless required by applicable law or agreed to in writing, software 11eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * distributed under the License is distributed on an "AS IS" BASIS, 12eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * See the License for the specific language governing permissions and 14eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * limitations under the License. 15eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad */ 16eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 17eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadpackage com.android.server.om; 18eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 19eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.annotation.NonNull; 20eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.annotation.Nullable; 21eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.content.om.IOverlayManager; 22eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.content.om.OverlayInfo; 23eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.RemoteException; 24eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.ShellCommand; 25eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.UserHandle; 26eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 27eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.io.PrintWriter; 28eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.util.List; 29eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.util.Map; 30eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 31eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad/** 32eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Implementation of 'cmd overlay' commands. 33eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * 34eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * This class provides an interface to the OverlayManagerService via adb. 35eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Intended only for manual debugging. Execute 'adb exec-out cmd overlay help' 36eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * for a list of available commands. 37eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad */ 38eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadfinal class OverlayManagerShellCommand extends ShellCommand { 39eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad private final IOverlayManager mInterface; 40eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 41eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad OverlayManagerShellCommand(@NonNull final IOverlayManager iom) { 42eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad mInterface = iom; 43eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 44eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 45eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad @Override 46eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad public int onCommand(@Nullable final String cmd) { 47eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad if (cmd == null) { 48eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return handleDefaultCommands(cmd); 49eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 50eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final PrintWriter err = getErrPrintWriter(); 51eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad try { 52eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad switch (cmd) { 53eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "list": 54eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return runList(); 55eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "enable": 56eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return runEnableDisable(true); 57eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "disable": 58eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return runEnableDisable(false); 59eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "set-priority": 60eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return runSetPriority(); 61eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad default: 62eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return handleDefaultCommands(cmd); 63eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 64eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } catch (IllegalArgumentException e) { 65eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad err.println("Error: " + e.getMessage()); 66eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } catch (RemoteException e) { 67eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad err.println("Remote exception: " + e); 68eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 69eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return -1; 70eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 71eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 72eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad @Override 73eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad public void onHelp() { 74eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final PrintWriter out = getOutPrintWriter(); 75eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println("Overlay manager (overlay) commands:"); 76eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" help"); 77eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Print this help text."); 78eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); 79eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Print debugging information about the overlay manager."); 80eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" list [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); 81eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Print information about target and overlay packages."); 82eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Overlay packages are printed in priority order. With optional"); 83eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" parameters PACKAGEs, limit output to the specified packages"); 84eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" but include more information about each package."); 85eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" enable [--user USER_ID] PACKAGE"); 86eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Enable overlay package PACKAGE."); 87eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" disable [--user USER_ID] PACKAGE"); 88eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Disable overlay package PACKAGE."); 89eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest"); 90eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" Change the priority of the overlay PACKAGE to be just higher than"); 91eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" the priority of PACKAGE_PARENT If PARENT is the special keyword"); 92eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" 'lowest', change priority of PACKAGE to the lowest priority."); 93eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" If PARENT is the special keyword 'highest', change priority of"); 94eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(" PACKAGE to the highest priority."); 95eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 96eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 97eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad private int runList() throws RemoteException { 98eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final PrintWriter out = getOutPrintWriter(); 99eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final PrintWriter err = getErrPrintWriter(); 100eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 101eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad int userId = UserHandle.USER_SYSTEM; 102eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad String opt; 103eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad while ((opt = getNextOption()) != null) { 104eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad switch (opt) { 105eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "--user": 106eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad userId = UserHandle.parseUserArg(getNextArgRequired()); 107eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad break; 108eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad default: 109eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad err.println("Error: Unknown option: " + opt); 110eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return 1; 111eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 112eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 113eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 114eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId); 115eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad for (final String targetPackageName : allOverlays.keySet()) { 116eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(targetPackageName); 117eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName); 118eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final int N = overlaysForTarget.size(); 119eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad for (int i = 0; i < N; i++) { 120eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final OverlayInfo oi = overlaysForTarget.get(i); 121eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad String status; 122eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad switch (oi.state) { 123eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case OverlayInfo.STATE_ENABLED: 124eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad status = "[x]"; 125eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad break; 126eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case OverlayInfo.STATE_DISABLED: 127eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad status = "[ ]"; 128eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad break; 129eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad default: 130eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad status = "---"; 131eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad break; 132eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 133eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(String.format("%s %s", status, oi.packageName)); 134eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 135eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad out.println(); 136eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 137eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return 0; 138eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 139eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 140eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad private int runEnableDisable(final boolean enable) throws RemoteException { 141eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final PrintWriter err = getErrPrintWriter(); 142eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 143eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad int userId = UserHandle.USER_SYSTEM; 144eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad String opt; 145eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad while ((opt = getNextOption()) != null) { 146eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad switch (opt) { 147eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "--user": 148eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad userId = UserHandle.parseUserArg(getNextArgRequired()); 149eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad break; 150eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad default: 151eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad err.println("Error: Unknown option: " + opt); 152eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return 1; 153eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 154eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 155eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 156eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final String packageName = getNextArgRequired(); 157eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1; 158eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 159eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 160eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad private int runSetPriority() throws RemoteException { 161eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final PrintWriter err = getErrPrintWriter(); 162eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 163eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad int userId = UserHandle.USER_SYSTEM; 164eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad String opt; 165eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad while ((opt = getNextOption()) != null) { 166eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad switch (opt) { 167eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad case "--user": 168eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad userId = UserHandle.parseUserArg(getNextArgRequired()); 169eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad break; 170eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad default: 171eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad err.println("Error: Unknown option: " + opt); 172eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return 1; 173eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 174eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 175eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 176eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final String packageName = getNextArgRequired(); 177eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad final String newParentPackageName = getNextArgRequired(); 178eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad 179eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad if ("highest".equals(newParentPackageName)) { 180eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return mInterface.setHighestPriority(packageName, userId) ? 0 : 1; 181eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } else if ("lowest".equals(newParentPackageName)) { 182eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return mInterface.setLowestPriority(packageName, userId) ? 0 : 1; 183eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } else { 184eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad return mInterface.setPriority(packageName, newParentPackageName, userId) ? 0 : 1; 185eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 186eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad } 187eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad} 188