Merge "Add command line support for testing tz detection"
This commit is contained in:
@@ -20,7 +20,9 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -127,4 +129,32 @@ public final class ManualTimeZoneSuggestion implements Parcelable {
|
||||
+ ", mDebugInfo=" + mDebugInfo
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static ManualTimeZoneSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) {
|
||||
String zoneId = null;
|
||||
String opt;
|
||||
while ((opt = cmd.getNextArg()) != null) {
|
||||
switch (opt) {
|
||||
case "--zone_id": {
|
||||
zoneId = cmd.getNextArgRequired();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown option: " + opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(zoneId);
|
||||
suggestion.addDebugInfo("Command line injection");
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static void printCommandLineOpts(@NonNull PrintWriter pw) {
|
||||
pw.println("Manual suggestion options:");
|
||||
pw.println(" --zone_id <Olson ID>");
|
||||
pw.println();
|
||||
pw.println("See " + ManualTimeZoneSuggestion.class.getName() + " for more information");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.ShellCommand;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
@@ -392,4 +395,96 @@ public final class TelephonyTimeZoneSuggestion implements Parcelable {
|
||||
return new TelephonyTimeZoneSuggestion(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static TelephonyTimeZoneSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
|
||||
throws IllegalArgumentException {
|
||||
Integer slotIndex = null;
|
||||
String zoneId = null;
|
||||
Integer quality = null;
|
||||
Integer matchType = null;
|
||||
String opt;
|
||||
while ((opt = cmd.getNextArg()) != null) {
|
||||
switch (opt) {
|
||||
case "--slot_index": {
|
||||
slotIndex = Integer.parseInt(cmd.getNextArgRequired());
|
||||
break;
|
||||
}
|
||||
case "--zone_id": {
|
||||
zoneId = cmd.getNextArgRequired();
|
||||
break;
|
||||
}
|
||||
case "--quality": {
|
||||
quality = parseQualityCommandLineArg(cmd.getNextArgRequired());
|
||||
break;
|
||||
}
|
||||
case "--match_type": {
|
||||
matchType = parseMatchTypeCommandLineArg(cmd.getNextArgRequired());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown option: " + opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (slotIndex == null) {
|
||||
throw new IllegalArgumentException("No slotIndex specified.");
|
||||
}
|
||||
|
||||
Builder builder = new Builder(slotIndex);
|
||||
if (!(TextUtils.isEmpty(zoneId) || "_".equals(zoneId))) {
|
||||
builder.setZoneId(zoneId);
|
||||
}
|
||||
if (quality != null) {
|
||||
builder.setQuality(quality);
|
||||
}
|
||||
if (matchType != null) {
|
||||
builder.setMatchType(matchType);
|
||||
}
|
||||
builder.addDebugInfo("Command line injection");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static int parseQualityCommandLineArg(@NonNull String arg) {
|
||||
switch (arg) {
|
||||
case "single":
|
||||
return QUALITY_SINGLE_ZONE;
|
||||
case "multiple_same":
|
||||
return QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
|
||||
case "multiple_different":
|
||||
return QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized quality: " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseMatchTypeCommandLineArg(@NonNull String arg) {
|
||||
switch (arg) {
|
||||
case "emulator":
|
||||
return MATCH_TYPE_EMULATOR_ZONE_ID;
|
||||
case "country_with_offset":
|
||||
return MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
|
||||
case "country":
|
||||
return MATCH_TYPE_NETWORK_COUNTRY_ONLY;
|
||||
case "test_network":
|
||||
return MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized match_type: " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static void printCommandLineOpts(@NonNull PrintWriter pw) {
|
||||
pw.println("Telephony suggestion options:");
|
||||
pw.println(" --slot_index <number>");
|
||||
pw.println(" To withdraw a previous suggestion:");
|
||||
pw.println(" [--zone_id \"_\"]");
|
||||
pw.println(" To make a new suggestion:");
|
||||
pw.println(" --zone_id <Olson ID>");
|
||||
pw.println(" --quality <single|multiple_same|multiple_different>");
|
||||
pw.println(" --match_type <emulator|country_with_offset|country|test_network>");
|
||||
pw.println();
|
||||
pw.println("See " + TelephonyTimeZoneSuggestion.class.getName() + " for more information");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,19 @@ package android.app.timezonedetector;
|
||||
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
|
||||
import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class ManualTimeZoneSuggestionTest {
|
||||
|
||||
private static final String ARBITRARY_ZONE_ID1 = "Europe/London";
|
||||
@@ -58,4 +65,36 @@ public class ManualTimeZoneSuggestionTest {
|
||||
ManualTimeZoneSuggestion rtSuggestion = roundTripParcelable(suggestion);
|
||||
assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrintCommandLineOpts() throws Exception {
|
||||
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
|
||||
ManualTimeZoneSuggestion.printCommandLineOpts(pw);
|
||||
assertTrue(sw.getBuffer().length() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_noArgs() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("");
|
||||
ManualTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_validSuggestion() {
|
||||
ShellCommand testShellCommand =
|
||||
createShellCommandWithArgsAndOptions("--zone_id Europe/London");
|
||||
ManualTimeZoneSuggestion expectedSuggestion =
|
||||
new ManualTimeZoneSuggestion("Europe/London");
|
||||
ManualTimeZoneSuggestion actualSuggestion =
|
||||
ManualTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
assertEquals(expectedSuggestion, actualSuggestion);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_unknownArgument() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
"--zone_id Europe/London --bad_arg 0");
|
||||
ManualTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.app.timezonedetector;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** Utility methods related to {@link ShellCommand} objects used in several tests. */
|
||||
final class ShellCommandTestSupport {
|
||||
private ShellCommandTestSupport() {}
|
||||
|
||||
static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
|
||||
return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
|
||||
}
|
||||
|
||||
static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
|
||||
ShellCommand command = mock(ShellCommand.class);
|
||||
class ArgProvider {
|
||||
private int mCount;
|
||||
|
||||
String getNext() {
|
||||
if (mCount >= args.size()) {
|
||||
return null;
|
||||
}
|
||||
return args.get(mCount++);
|
||||
}
|
||||
|
||||
String getNextRequired() {
|
||||
String next = getNext();
|
||||
if (next == null) {
|
||||
throw new IllegalArgumentException("No next");
|
||||
}
|
||||
return next;
|
||||
}
|
||||
}
|
||||
ArgProvider argProvider = new ArgProvider();
|
||||
when(command.getNextArg()).thenAnswer(
|
||||
(Answer<String>) invocation -> argProvider.getNext());
|
||||
when(command.getNextOption()).thenAnswer(
|
||||
(Answer<String>) invocation -> argProvider.getNext());
|
||||
when(command.getNextArgRequired()).thenAnswer(
|
||||
(Answer<String>) invocation -> argProvider.getNextRequired());
|
||||
return command;
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,19 @@ package android.app.timezonedetector;
|
||||
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
|
||||
import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class TelephonyTimeZoneSuggestionTest {
|
||||
private static final int SLOT_INDEX = 99999;
|
||||
|
||||
@@ -159,4 +165,57 @@ public class TelephonyTimeZoneSuggestionTest {
|
||||
assertEquals(suggestion1, suggestion1_2);
|
||||
assertTrue(suggestion1_2.getDebugInfo().contains(debugString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrintCommandLineOpts() throws Exception {
|
||||
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
|
||||
TelephonyTimeZoneSuggestion.printCommandLineOpts(pw);
|
||||
assertTrue(sw.getBuffer().length() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_noArgs() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("");
|
||||
TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_noSlotIndex() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("--zone_id _");
|
||||
TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_validEmptyZoneIdSuggestion() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
"--slot_index 0 --zone_id _");
|
||||
TelephonyTimeZoneSuggestion expectedSuggestion =
|
||||
new TelephonyTimeZoneSuggestion.Builder(0).build();
|
||||
TelephonyTimeZoneSuggestion actualSuggestion =
|
||||
TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
assertEquals(expectedSuggestion, actualSuggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_validNonEmptySuggestion() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
"--slot_index 0 --zone_id Europe/London --quality single --match_type country");
|
||||
TelephonyTimeZoneSuggestion expectedSuggestion =
|
||||
new TelephonyTimeZoneSuggestion.Builder(0)
|
||||
.setZoneId("Europe/London")
|
||||
.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
|
||||
.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY)
|
||||
.build();
|
||||
TelephonyTimeZoneSuggestion actualSuggestion =
|
||||
TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
assertEquals(expectedSuggestion, actualSuggestion);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_unknownArgument() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
"--slot_index 0 --zone_id _ --bad_arg 0");
|
||||
TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -133,5 +135,13 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE,
|
||||
"suggest manual time and time zone");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShellCommand(FileDescriptor in, FileDescriptor out,
|
||||
FileDescriptor err, String[] args, ShellCallback callback,
|
||||
ResultReceiver resultReceiver) {
|
||||
(new TimeZoneDetectorShellCommand(this)).exec(
|
||||
this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/** Implemented the shell command interface for {@link TimeZoneDetectorService}. */
|
||||
class TimeZoneDetectorShellCommand extends ShellCommand {
|
||||
|
||||
private final TimeZoneDetectorService mInterface;
|
||||
|
||||
TimeZoneDetectorShellCommand(TimeZoneDetectorService timeZoneDetectorService) {
|
||||
mInterface = timeZoneDetectorService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
if (cmd == null) {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case "suggestTelephonyTimeZone":
|
||||
return runSuggestTelephonyTimeZone();
|
||||
case "suggestManualTimeZone":
|
||||
return runSuggestManualTimeZone();
|
||||
default: {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int runSuggestTelephonyTimeZone() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
try {
|
||||
TelephonyTimeZoneSuggestion suggestion = null;
|
||||
String opt;
|
||||
while ((opt = getNextArg()) != null) {
|
||||
if ("--suggestion".equals(opt)) {
|
||||
suggestion = TelephonyTimeZoneSuggestion.parseCommandLineArg(this);
|
||||
} else {
|
||||
pw.println("Error: Unknown option: " + opt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (suggestion == null) {
|
||||
pw.println("Error: suggestion not specified");
|
||||
return 1;
|
||||
}
|
||||
mInterface.suggestTelephonyTimeZone(suggestion);
|
||||
pw.println("Suggestion " + suggestion + " injected.");
|
||||
return 0;
|
||||
} catch (RuntimeException e) {
|
||||
pw.println(e.toString());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private int runSuggestManualTimeZone() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
try {
|
||||
ManualTimeZoneSuggestion suggestion = null;
|
||||
String opt;
|
||||
while ((opt = getNextArg()) != null) {
|
||||
if ("--suggestion".equals(opt)) {
|
||||
suggestion = ManualTimeZoneSuggestion.parseCommandLineArg(this);
|
||||
} else {
|
||||
pw.println("Error: Unknown option: " + opt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (suggestion == null) {
|
||||
pw.println("Error: suggestion not specified");
|
||||
return 1;
|
||||
}
|
||||
mInterface.suggestManualTimeZone(suggestion);
|
||||
pw.println("Suggestion " + suggestion + " injected.");
|
||||
return 0;
|
||||
} catch (RuntimeException e) {
|
||||
pw.println(e.toString());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
pw.println("Time Zone Detector (time_zone_detector) commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Print this help text.");
|
||||
pw.println(" suggestTelephonyTimeZone");
|
||||
pw.println(" --suggestion <telephony suggestion opts>");
|
||||
pw.println(" suggestManualTimeZone");
|
||||
pw.println(" --suggestion <manual suggestion opts>");
|
||||
pw.println();
|
||||
ManualTimeZoneSuggestion.printCommandLineOpts(pw);
|
||||
pw.println();
|
||||
TelephonyTimeZoneSuggestion.printCommandLineOpts(pw);
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user