未验证 提交 14e41878 编写于 作者: S Shi-Hao Hong 提交者: GitHub

Incorporate View.setSystemGestureExclusionRects code review feedback from #11441 (#11804)

* Improve variable naming and javadoc for setSystemGestureExclusionRects

* Remove variables from setSystemGestureExclusionRects tests

* Split test for two behaviors into two separate tests for setSystemGestureExclusionRects success case
上级 8f4a0a7c
......@@ -37,7 +37,151 @@ public class PlatformChannel {
private PlatformMessageHandler platformMessageHandler;
@NonNull
@VisibleForTesting
protected final PlatformMethodCallHandler parsingMethodCallHandler = new PlatformMethodCallHandler();
protected final MethodChannel.MethodCallHandler parsingMethodCallHandler = new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (platformMessageHandler == null) {
// If no explicit PlatformMessageHandler has been registered then we don't
// need to forward this call to an API. Return.
return;
}
String method = call.method;
Object arguments = call.arguments;
Log.v(TAG, "Received '" + method + "' message.");
try {
switch (method) {
case "SystemSound.play":
try {
SoundType soundType = SoundType.fromValue((String) arguments);
platformMessageHandler.playSystemSound(soundType);
result.success(null);
} catch (NoSuchFieldException exception) {
// The desired sound type does not exist.
result.error("error", exception.getMessage(), null);
}
break;
case "HapticFeedback.vibrate":
try {
HapticFeedbackType feedbackType = HapticFeedbackType.fromValue((String) arguments);
platformMessageHandler.vibrateHapticFeedback(feedbackType);
result.success(null);
} catch (NoSuchFieldException exception) {
// The desired feedback type does not exist.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.setPreferredOrientations":
try {
int androidOrientation = decodeOrientations((JSONArray) arguments);
platformMessageHandler.setPreferredOrientations(androidOrientation);
result.success(null);
} catch (JSONException | NoSuchFieldException exception) {
// JSONException: One or more expected fields were either omitted or referenced an invalid type.
// NoSuchFieldException: One or more expected fields were either omitted or referenced an invalid type.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.setApplicationSwitcherDescription":
try {
AppSwitcherDescription description = decodeAppSwitcherDescription((JSONObject) arguments);
platformMessageHandler.setApplicationSwitcherDescription(description);
result.success(null);
} catch (JSONException exception) {
// One or more expected fields were either omitted or referenced an invalid type.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.setEnabledSystemUIOverlays":
try {
List<SystemUiOverlay> overlays = decodeSystemUiOverlays((JSONArray) arguments);
platformMessageHandler.showSystemOverlays(overlays);
result.success(null);
} catch (JSONException | NoSuchFieldException exception) {
// JSONException: One or more expected fields were either omitted or referenced an invalid type.
// NoSuchFieldException: One or more of the overlay names are invalid.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.restoreSystemUIOverlays":
platformMessageHandler.restoreSystemUiOverlays();
result.success(null);
break;
case "SystemChrome.setSystemUIOverlayStyle":
try {
SystemChromeStyle systemChromeStyle = decodeSystemChromeStyle((JSONObject) arguments);
platformMessageHandler.setSystemUiOverlayStyle(systemChromeStyle);
result.success(null);
} catch (JSONException | NoSuchFieldException exception) {
// JSONException: One or more expected fields were either omitted or referenced an invalid type.
// NoSuchFieldException: One or more of the brightness names are invalid.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemNavigator.pop":
platformMessageHandler.popSystemNavigator();
result.success(null);
break;
case "SystemGestures.getSystemGestureExclusionRects":
List<Rect> exclusionRects = platformMessageHandler.getSystemGestureExclusionRects();
if (exclusionRects == null) {
String incorrectApiLevel = "Exclusion rects only exist for Android API 29+.";
result.error("error", incorrectApiLevel, null);
break;
}
ArrayList<HashMap<String, Integer>> encodedExclusionRects = encodeExclusionRects(exclusionRects);
result.success(encodedExclusionRects);
break;
case "SystemGestures.setSystemGestureExclusionRects":
if (!(arguments instanceof JSONArray)) {
String inputTypeError = "Input type is incorrect. Ensure that a List<Map<String, int>> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects.";
result.error("inputTypeError", inputTypeError, null);
break;
}
JSONArray inputRects = (JSONArray) arguments;
ArrayList<Rect> decodedRects = decodeExclusionRects(inputRects);
platformMessageHandler.setSystemGestureExclusionRects(decodedRects);
result.success(null);
break;
case "Clipboard.getData": {
String contentFormatName = (String) arguments;
ClipboardContentFormat clipboardFormat = null;
if (contentFormatName != null) {
try {
clipboardFormat = ClipboardContentFormat.fromValue(contentFormatName);
} catch (NoSuchFieldException exception) {
// An unsupported content format was requested. Return failure.
result.error("error", "No such clipboard content format: " + contentFormatName, null);
}
}
CharSequence clipboardContent = platformMessageHandler.getClipboardData(clipboardFormat);
if (clipboardContent != null) {
JSONObject response = new JSONObject();
response.put("text", clipboardContent);
result.success(response);
} else {
result.success(null);
}
break;
}
case "Clipboard.setData": {
String clipboardContent = ((JSONObject) arguments).getString("text");
platformMessageHandler.setClipboardData(clipboardContent);
result.success(null);
break;
}
default:
result.notImplemented();
break;
}
} catch (JSONException e) {
result.error("error", "JSON error: " + e.getMessage(), null);
}
}
};
/**
* Constructs a {@code PlatformChannel} that connects Android to the Dart code
......@@ -143,6 +287,13 @@ public class PlatformChannel {
/**
* Decodes a JSONArray of rectangle data into an ArrayList<Rect>.
*
* Since View.setSystemGestureExclusionRects receives a JSONArray containing
* JSONObjects, these values need to be transformed into the expected input
* of View.setSystemGestureExclusionRects, which is ArrayList<Rect>.
*
* This method is used by the SystemGestures.setSystemGestureExclusionRects
* platform channel.
*
* @throws JSONException if {@code inputRects} does not contain expected keys and value types.
*/
@NonNull
......@@ -535,159 +686,6 @@ public class PlatformChannel {
}
}
/**
* A handler of incoming platform channel method calls received from Flutter.
* It first determines the platform's API to be called. If it exists, it then
* decodes incoming arguments, if needed, into a format that is necessary for the API.
*/
@VisibleForTesting
protected class PlatformMethodCallHandler implements MethodChannel.MethodCallHandler {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (platformMessageHandler == null) {
// If no explicit PlatformMessageHandler has been registered then we don't
// need to forward this call to an API. Return.
return;
}
String method = call.method;
Object arguments = call.arguments;
Log.v(TAG, "Received '" + method + "' message.");
try {
switch (method) {
case "SystemSound.play":
try {
SoundType soundType = SoundType.fromValue((String) arguments);
platformMessageHandler.playSystemSound(soundType);
result.success(null);
} catch (NoSuchFieldException exception) {
// The desired sound type does not exist.
result.error("error", exception.getMessage(), null);
}
break;
case "HapticFeedback.vibrate":
try {
HapticFeedbackType feedbackType = HapticFeedbackType.fromValue((String) arguments);
platformMessageHandler.vibrateHapticFeedback(feedbackType);
result.success(null);
} catch (NoSuchFieldException exception) {
// The desired feedback type does not exist.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.setPreferredOrientations":
try {
int androidOrientation = decodeOrientations((JSONArray) arguments);
platformMessageHandler.setPreferredOrientations(androidOrientation);
result.success(null);
} catch (JSONException | NoSuchFieldException exception) {
// JSONException: One or more expected fields were either omitted or referenced an invalid type.
// NoSuchFieldException: One or more expected fields were either omitted or referenced an invalid type.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.setApplicationSwitcherDescription":
try {
AppSwitcherDescription description = decodeAppSwitcherDescription((JSONObject) arguments);
platformMessageHandler.setApplicationSwitcherDescription(description);
result.success(null);
} catch (JSONException exception) {
// One or more expected fields were either omitted or referenced an invalid type.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.setEnabledSystemUIOverlays":
try {
List<SystemUiOverlay> overlays = decodeSystemUiOverlays((JSONArray) arguments);
platformMessageHandler.showSystemOverlays(overlays);
result.success(null);
} catch (JSONException | NoSuchFieldException exception) {
// JSONException: One or more expected fields were either omitted or referenced an invalid type.
// NoSuchFieldException: One or more of the overlay names are invalid.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemChrome.restoreSystemUIOverlays":
platformMessageHandler.restoreSystemUiOverlays();
result.success(null);
break;
case "SystemChrome.setSystemUIOverlayStyle":
try {
SystemChromeStyle systemChromeStyle = decodeSystemChromeStyle((JSONObject) arguments);
platformMessageHandler.setSystemUiOverlayStyle(systemChromeStyle);
result.success(null);
} catch (JSONException | NoSuchFieldException exception) {
// JSONException: One or more expected fields were either omitted or referenced an invalid type.
// NoSuchFieldException: One or more of the brightness names are invalid.
result.error("error", exception.getMessage(), null);
}
break;
case "SystemNavigator.pop":
platformMessageHandler.popSystemNavigator();
result.success(null);
break;
case "Clipboard.getData": {
String contentFormatName = (String) arguments;
ClipboardContentFormat clipboardFormat = null;
if (contentFormatName != null) {
try {
clipboardFormat = ClipboardContentFormat.fromValue(contentFormatName);
} catch (NoSuchFieldException exception) {
// An unsupported content format was requested. Return failure.
result.error("error", "No such clipboard content format: " + contentFormatName, null);
}
}
CharSequence clipboardContent = platformMessageHandler.getClipboardData(clipboardFormat);
if (clipboardContent != null) {
JSONObject response = new JSONObject();
response.put("text", clipboardContent);
result.success(response);
} else {
result.success(null);
}
break;
}
case "Clipboard.setData": {
String clipboardContent = ((JSONObject) arguments).getString("text");
platformMessageHandler.setClipboardData(clipboardContent);
result.success(null);
break;
}
case "SystemGestures.setSystemGestureExclusionRects":
if (!(arguments instanceof JSONArray)) {
String inputTypeError = "Input type is incorrect. Ensure that a List<Map<String, int>> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects.";
result.error("inputTypeError", inputTypeError, null);
break;
}
JSONArray inputRects = (JSONArray) arguments;
ArrayList<Rect> decodedRects = decodeExclusionRects(inputRects);
platformMessageHandler.setSystemGestureExclusionRects(decodedRects);
result.success(null);
break;
case "SystemGestures.getSystemGestureExclusionRects": {
List<Rect> exclusionRects = platformMessageHandler.getSystemGestureExclusionRects();
if (exclusionRects == null) {
String incorrectApiLevel = "Exclusion rects only exist for Android API 29+.";
result.error("error", incorrectApiLevel, null);
break;
}
ArrayList<HashMap<String, Integer>> encodedExclusionRects = encodeExclusionRects(exclusionRects);
result.success(encodedExclusionRects);
break;
}
default:
result.notImplemented();
break;
}
} catch (JSONException e) {
result.error("error", "JSON error: " + e.getMessage(), null);
}
}
}
public enum Brightness {
LIGHT("Brightness.light"),
DARK("Brightness.dark");
......
......@@ -28,95 +28,97 @@ import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
public class PlatformChannelTest {
@Test
public void setSystemExclusionRectsSendsSuccessMessageToFramework() throws JSONException {
public void itSendsSuccessMessageToFrameworkWhenGettingSystemGestureExclusionRects() throws JSONException {
// --- Test Setup ---
DartExecutor dartExecutor = mock(DartExecutor.class);
PlatformChannel platformChannel = new PlatformChannel(dartExecutor);
PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class);
platformChannel.setPlatformMessageHandler(platformMessageHandler);
Result result = mock(Result.class);
int top = 0;
int right = 500;
int bottom = 250;
int left = 0;
ResultsMock resultsMock = mock(ResultsMock.class);
JSONObject JsonRect = new JSONObject();
JsonRect.put("top", top);
JsonRect.put("right", right);
JsonRect.put("bottom", bottom);
JsonRect.put("left", left);
JSONArray inputRects = new JSONArray();
inputRects.put(JsonRect);
ArrayList<Rect> expectedDecodedRects = new ArrayList<Rect>();
Rect gestureRect = new Rect(left, top, right, bottom);
expectedDecodedRects.add(gestureRect);
// Fake API output setup
ArrayList<Rect> fakeExclusionRects = new ArrayList<Rect>();
Rect gestureRect = new Rect(0, 0, 500, 250);
fakeExclusionRects.add(gestureRect);
when(platformMessageHandler.getSystemGestureExclusionRects()).thenReturn(fakeExclusionRects);
MethodCall callSetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.setSystemGestureExclusionRects",
inputRects
// Parsed API output that should be passed to result.success()
ArrayList<HashMap<String, Integer>> expectedEncodedOutputRects = new ArrayList<HashMap<String, Integer>>();
HashMap<String, Integer> rectMap = new HashMap<String, Integer>();
rectMap.put("top", 0);
rectMap.put("right", 500);
rectMap.put("bottom", 250);
rectMap.put("left", 0);
expectedEncodedOutputRects.add(rectMap);
MethodCall callGetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.getSystemGestureExclusionRects",
null
);
platformChannel.parsingMethodCallHandler.onMethodCall(callSetSystemGestureExclusionRects, resultsMock);
verify(platformMessageHandler, times(1)).setSystemGestureExclusionRects(expectedDecodedRects);
verify(resultsMock, times(1)).success(null);
// --- Execute Test ---
platformChannel.parsingMethodCallHandler.onMethodCall(callGetSystemGestureExclusionRects, result);
// --- Verify Results ---
verify(result, times(1)).success(expectedEncodedOutputRects);
}
@Test
public void setSystemExclusionRectsRequiresJSONArrayInput() {
public void itSendsAPILevelErrorWhenAndroidVersionIsTooLowWhenGettingSystemGestureExclusionRects() {
// --- Test Setup ---
DartExecutor dartExecutor = mock(DartExecutor.class);
PlatformChannel platformChannel = new PlatformChannel(dartExecutor);
PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class);
platformChannel.setPlatformMessageHandler(platformMessageHandler);
when(platformMessageHandler.getSystemGestureExclusionRects()).thenReturn(null);
Result result = mock(Result.class);
ResultsMock resultsMock = mock(ResultsMock.class);
String nonJsonInput = "Non-JSON";
MethodCall callSetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.setSystemGestureExclusionRects",
nonJsonInput
MethodCall callGetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.getSystemGestureExclusionRects",
null
);
platformChannel.parsingMethodCallHandler.onMethodCall(callSetSystemGestureExclusionRects, resultsMock);
String inputTypeError = "Input type is incorrect. Ensure that a List<Map<String, int>> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects.";
verify(resultsMock, times(1)).error(
"inputTypeError",
inputTypeError,
// --- Execute Test ---
platformChannel.parsingMethodCallHandler.onMethodCall(callGetSystemGestureExclusionRects, result);
// --- Verify Results ---
verify(result, times(1)).error(
"error",
"Exclusion rects only exist for Android API 29+.",
null
);
}
@Test
public void setSystemExclusionRectsSendsJSONExceptionOnIncorrectDataShape() throws JSONException {
public void itSendsSuccessMessageToFrameworkWhenSettingSystemGestureExclusionRects() throws JSONException {
// --- Test Setup ---
DartExecutor dartExecutor = mock(DartExecutor.class);
PlatformChannel platformChannel = new PlatformChannel(dartExecutor);
PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class);
platformChannel.setPlatformMessageHandler(platformMessageHandler);
Result result = mock(Result.class);
int top = 0;
int right = 500;
ResultsMock resultsMock = mock(ResultsMock.class);
JSONObject jsonObject = new JSONObject();
jsonObject.put("arg1", top);
jsonObject.put("arg2", right);
JSONArray inputArray = new JSONArray();
inputArray.put(jsonObject);
JSONObject jsonRect = new JSONObject();
jsonRect.put("top", 0);
jsonRect.put("right", 500);
jsonRect.put("bottom", 250);
jsonRect.put("left", 0);
JSONArray jsonExclusionRectsFromPlatform = new JSONArray();
jsonExclusionRectsFromPlatform.put(jsonRect);
MethodCall callSetSystemGestureExclusionRects = new MethodCall(
MethodCall callSystemGestureExclusionRects = new MethodCall(
"SystemGestures.setSystemGestureExclusionRects",
inputArray
);
platformChannel.parsingMethodCallHandler.onMethodCall(callSetSystemGestureExclusionRects, resultsMock);
verify(resultsMock, times(1)).error(
"error",
"JSON error: Incorrect JSON data shape. To set system gesture exclusion rects, \n" +
"a JSONObject with top, right, bottom and left values need to be set to int values.",
null
jsonExclusionRectsFromPlatform
);
// --- Execute Test ---
platformChannel.parsingMethodCallHandler.onMethodCall(callSystemGestureExclusionRects, result);
// --- Verify Results ---
verify(result, times(1)).success(null);
}
@Test
public void itSendsSuccessMessageToFrameworkWhenGettingSystemGestureExclusionRects() throws JSONException {
public void itProperlyDecodesGestureRectsWhenSettingSystemGestureExclusionRects() throws JSONException {
// --- Test Setup ---
DartExecutor dartExecutor = mock(DartExecutor.class);
PlatformChannel platformChannel = new PlatformChannel(dartExecutor);
......@@ -124,66 +126,87 @@ public class PlatformChannelTest {
platformChannel.setPlatformMessageHandler(platformMessageHandler);
Result result = mock(Result.class);
// Fake API output setup
ArrayList<Rect> fakeExclusionRects = new ArrayList<Rect>();
JSONObject jsonRect = new JSONObject();
jsonRect.put("top", 0);
jsonRect.put("right", 500);
jsonRect.put("bottom", 250);
jsonRect.put("left", 0);
JSONArray jsonExclusionRectsFromPlatform = new JSONArray();
jsonExclusionRectsFromPlatform.put(jsonRect);
ArrayList<Rect> expectedDecodedRects = new ArrayList<Rect>();
Rect gestureRect = new Rect(0, 0, 500, 250);
fakeExclusionRects.add(gestureRect);
when(platformMessageHandler.getSystemGestureExclusionRects()).thenReturn(fakeExclusionRects);
expectedDecodedRects.add(gestureRect);
// Parsed API output that should be passed to result.success()
ArrayList<HashMap<String, Integer>> expectedEncodedOutputRects = new ArrayList<HashMap<String, Integer>>();
HashMap<String, Integer> rectMap = new HashMap<String, Integer>();
rectMap.put("top", 0);
rectMap.put("right", 500);
rectMap.put("bottom", 250);
rectMap.put("left", 0);
expectedEncodedOutputRects.add(rectMap);
MethodCall callGetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.getSystemGestureExclusionRects",
null
MethodCall callSetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.setSystemGestureExclusionRects",
jsonExclusionRectsFromPlatform
);
// --- Execute Test ---
platformChannel.parsingMethodCallHandler.onMethodCall(callGetSystemGestureExclusionRects, result);
platformChannel.parsingMethodCallHandler.onMethodCall(callSetSystemGestureExclusionRects, result);
// --- Verify Results ---
verify(result, times(1)).success(expectedEncodedOutputRects);
verify(platformMessageHandler, times(1)).setSystemGestureExclusionRects(expectedDecodedRects);
}
@Test
public void itSendsAPILevelErrorWhenAndroidVersionIsTooLowWhenGettingSystemGestureExclusionRects() {
public void itSendsJSONInputErrorWhenNonJSONInputIsUsedWhenSettingSystemGestureExclusionRects() {
// --- Test Setup ---
DartExecutor dartExecutor = mock(DartExecutor.class);
PlatformChannel platformChannel = new PlatformChannel(dartExecutor);
PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class);
platformChannel.setPlatformMessageHandler(platformMessageHandler);
when(platformMessageHandler.getSystemGestureExclusionRects()).thenReturn(null);
Result result = mock(Result.class);
MethodCall callGetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.getSystemGestureExclusionRects",
null
String nonJsonInput = "Non-JSON";
MethodCall callSetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.setSystemGestureExclusionRects",
nonJsonInput
);
// --- Execute Test ---
platformChannel.parsingMethodCallHandler.onMethodCall(callGetSystemGestureExclusionRects, result);
platformChannel.parsingMethodCallHandler.onMethodCall(callSetSystemGestureExclusionRects, result);
// --- Verify Results ---
String inputTypeError = "Input type is incorrect. Ensure that a List<Map<String, int>> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects.";
verify(result, times(1)).error(
"error",
"Exclusion rects only exist for Android API 29+.",
"inputTypeError",
inputTypeError,
null
);
}
private class ResultsMock implements Result {
@Override
public void success(Object result) {}
@Test
public void itSendsJSONErrorWhenIncorrectJSONShapeIsUsedWhenSettingSystemGestureExclusionRects() throws JSONException {
// --- Test Setup ---
DartExecutor dartExecutor = mock(DartExecutor.class);
PlatformChannel platformChannel = new PlatformChannel(dartExecutor);
PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class);
platformChannel.setPlatformMessageHandler(platformMessageHandler);
Result result = mock(Result.class);
// Add key/value pairs that aren't needed by exclusion rects to simulate incorrect JSON shape
JSONObject jsonObject = new JSONObject();
jsonObject.put("arg1", 0);
jsonObject.put("arg2", 500);
JSONArray inputArray = new JSONArray();
inputArray.put(jsonObject);
MethodCall callSetSystemGestureExclusionRects = new MethodCall(
"SystemGestures.setSystemGestureExclusionRects",
inputArray
);
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {}
// --- Execute Test ---
platformChannel.parsingMethodCallHandler.onMethodCall(callSetSystemGestureExclusionRects, result);
@Override
public void notImplemented() {}
// --- Verify Results ---
verify(result, times(1)).error(
"error",
"JSON error: Incorrect JSON data shape. To set system gesture exclusion rects, \n" +
"a JSONObject with top, right, bottom and left values need to be set to int values.",
null
);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册