diff --git a/FtcRobotController/build.gradle b/FtcRobotController/build.gradle
index 088a48df28f..b73fbe4f1a9 100644
--- a/FtcRobotController/build.gradle
+++ b/FtcRobotController/build.gradle
@@ -1,5 +1,3 @@
-import java.util.regex.Pattern
-
//
// build.gradle in FtcRobotController
//
@@ -13,7 +11,8 @@ android {
}
compileSdkVersion 23
- buildToolsVersion '23.0.3'
+ buildToolsVersion '25.0.3'
+
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
diff --git a/FtcRobotController/src/main/AndroidManifest.xml b/FtcRobotController/src/main/AndroidManifest.xml
index cfd5c04dc57..4adcc418e00 100644
--- a/FtcRobotController/src/main/AndroidManifest.xml
+++ b/FtcRobotController/src/main/AndroidManifest.xml
@@ -2,8 +2,8 @@
+ android:versionCode="24"
+ android:versionName="3.4">
@@ -12,7 +12,7 @@
android:largeHeap="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
- android:theme="@style/AppTheme" >
+ android:theme="@style/AppThemeRedRC" >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptCompassCalibration.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptCompassCalibration.java
index ff3ef8eb63a..3c870b4e94e 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptCompassCalibration.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptCompassCalibration.java
@@ -32,12 +32,10 @@ are permitted (subject to the limitations in the disclaimer below) provided that
*/
package org.firstinspires.ftc.robotcontroller.external.samples;
-import com.qualcomm.ftccommon.DbgLog;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.CompassSensor;
-import com.qualcomm.robotcore.hardware.LightSensor;
import com.qualcomm.robotcore.util.ElapsedTime;
/**
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorAdafruitRGB.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorAdafruitRGB.java
index bae1c6d238e..6ff3026af1a 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorAdafruitRGB.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorAdafruitRGB.java
@@ -35,7 +35,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import android.graphics.Color;
import android.view.View;
-import com.qualcomm.ftccommon.DbgLog;
import com.qualcomm.ftcrobotcontroller.R;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorBNO055IMUCalibration.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorBNO055IMUCalibration.java
index a4a0c775fd2..365b3a94c07 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorBNO055IMUCalibration.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorBNO055IMUCalibration.java
@@ -44,7 +44,7 @@ are permitted (subject to the limitations in the disclaimer below) provided that
import org.firstinspires.ftc.robotcore.external.navigation.AxesOrder;
import org.firstinspires.ftc.robotcore.external.navigation.AxesReference;
import org.firstinspires.ftc.robotcore.external.navigation.Orientation;
-import org.firstinspires.ftc.robotcore.internal.AppUtil;
+import org.firstinspires.ftc.robotcore.internal.system.AppUtil;
import java.io.File;
import java.util.Locale;
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorColor.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorColor.java
index aed151d08a8..fbfe9ef69b5 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorColor.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorColor.java
@@ -44,7 +44,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import com.qualcomm.robotcore.hardware.NormalizedRGBA;
import com.qualcomm.robotcore.hardware.SwitchableLight;
-import org.firstinspires.ftc.robotcore.internal.AppUtil;
+import org.firstinspires.ftc.robotcore.internal.system.AppUtil;
/*
* This is an example LinearOpMode that shows how to use a color sensor in a generic
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorDigitalTouch.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorDigitalTouch.java
new file mode 100644
index 00000000000..26be862e33a
--- /dev/null
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorDigitalTouch.java
@@ -0,0 +1,91 @@
+/* Copyright (c) 2017 FIRST.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted (subject to the limitations in the disclaimer below) provided that
+the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+Neither the name of Qualcomm Technologies Inc nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
+LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package org.firstinspires.ftc.robotcontroller.external.samples;
+
+import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
+import com.qualcomm.robotcore.eventloop.opmode.Disabled;
+import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
+import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
+import com.qualcomm.robotcore.hardware.DigitalChannel;
+
+/*
+ * This is an example LinearOpMode that shows how to use
+ * a REV Robotics Touch Sensor.
+ *
+ * It assumes that the touch sensor is configured with a name of "digitalTouch".
+ *
+ * Use Android Studio to Copy this Class, and Paste it into your team's code folder with a new name.
+ * Remove or comment out the @Disabled line to add this opmode to the Driver Station OpMode list.
+ */
+@Autonomous(name = "Sensor: Digital touch", group = "Sensor")
+@Disabled
+public class SensorDigitalTouch extends LinearOpMode {
+ /**
+ * The REV Robotics Touch Sensor
+ * is treated as a digital channel. It is HIGH if the button is unpressed.
+ * It pulls LOW if the button is pressed.
+ *
+ * Also, when you connect a REV Robotics Touch Sensor to the digital I/O port on the
+ * Expansion Hub using a 4-wire JST cable, the second pin gets connected to the Touch Sensor.
+ * The lower (first) pin stays unconnected.*
+ */
+
+ DigitalChannel digitalTouch; // Hardware Device Object
+
+ @Override
+ public void runOpMode() {
+
+ // get a reference to our digitalTouch object.
+ digitalTouch = hardwareMap.get(DigitalChannel.class, "digitalTouch");
+
+ // set the digital channel to input.
+ digitalTouch.setMode(DigitalChannel.Mode.INPUT);
+
+ // wait for the start button to be pressed.
+ waitForStart();
+
+ // while the op mode is active, loop and read the light levels.
+ // Note we use opModeIsActive() as our loop condition because it is an interruptible method.
+ while (opModeIsActive()) {
+
+ // send the info back to driver station using telemetry function.
+ // if the digital channel returns true it's HIGH and the button is unpressed.
+ if (digitalTouch.getState() == true) {
+ telemetry.addData("Digital Touch", "Is Not Pressed");
+ } else {
+ telemetry.addData("Digital Touch", "Is Pressed");
+ }
+
+ telemetry.update();
+ }
+ }
+}
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorREVColorDistance.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorREVColorDistance.java
new file mode 100644
index 00000000000..db3e793bf5f
--- /dev/null
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorREVColorDistance.java
@@ -0,0 +1,143 @@
+/* Copyright (c) 2017 FIRST.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted (subject to the limitations in the disclaimer below) provided that
+the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+Neither the name of Qualcomm Technologies Inc nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
+LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package org.firstinspires.ftc.robotcontroller.external.samples;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.view.View;
+
+import com.qualcomm.ftcrobotcontroller.R;
+import com.qualcomm.hardware.lynx.LynxI2cColorRangeSensor;
+import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
+import com.qualcomm.robotcore.eventloop.opmode.Disabled;
+import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
+import com.qualcomm.robotcore.hardware.ColorSensor;
+import com.qualcomm.robotcore.hardware.DeviceInterfaceModule;
+import com.qualcomm.robotcore.hardware.DigitalChannelController;
+import com.qualcomm.robotcore.hardware.DistanceSensor;
+
+import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
+
+import java.util.Locale;
+
+/*
+ * This is an example LinearOpMode that shows how to use
+ * the REV Robotics Color-Distance Sensor.
+ *
+ * It assumes the sensor is configured with the name "sensorColorDistance".
+ *
+ * Use Android Studio to Copy this Class, and Paste it into your team's code folder with a new name.
+ * Remove or comment out the @Disabled line to add this opmode to the Driver Station OpMode list.
+ */
+@Autonomous(name = "Sensor: REVColorDistance", group = "Sensor")
+@Disabled // Comment this out to add to the opmode list
+public class SensorREVColorDistance extends LinearOpMode {
+
+ /**
+ * Note that the REV Robotics Color-Distance incorporates two sensors into one device.
+ * It has a light/distance (range) sensor. It also has an RGB color sensor.
+ * The light/distance sensor saturates at around 2" (5cm). This means that targets that are 2"
+ * or closer will display the same value for distance/light detected.
+ *
+ * Although you configure a single REV Robotics Color-Distance sensor in your configuration file,
+ * you can treat the sensor as two separate sensors that share the same name in your op mode.
+ *
+ * In this example, we represent the detected color by a hue, saturation, and value color
+ * model (see https://en.wikipedia.org/wiki/HSL_and_HSV). We change the background
+ * color of the screen to match the detected color.
+ *
+ * In this example, we also use the distance sensor to display the distance
+ * to the target object. Note that the distance sensor saturates at around 2" (5 cm).
+ *
+ */
+ ColorSensor sensorColor;
+ DistanceSensor sensorDistance;
+
+ @Override
+ public void runOpMode() {
+
+ // get a reference to the color sensor.
+ sensorColor = hardwareMap.get(ColorSensor.class, "sensorColorDistance");
+
+ // get a reference to the distance sensor that shares the same name.
+ sensorDistance = hardwareMap.get(DistanceSensor.class, "sensorColorDistance");
+
+ // hsvValues is an array that will hold the hue, saturation, and value information.
+ float hsvValues[] = {0F, 0F, 0F};
+
+ // values is a reference to the hsvValues array.
+ final float values[] = hsvValues;
+
+ // sometimes it helps to multiply the raw RGB values with a scale factor
+ // to amplify/attentuate the measured values.
+ final double SCALE_FACTOR = 255;
+
+ // get a reference to the RelativeLayout so we can change the background
+ // color of the Robot Controller app to match the hue detected by the RGB sensor.
+ final View relativeLayout = ((Activity) hardwareMap.appContext).findViewById(R.id.RelativeLayout);
+
+ // wait for the start button to be pressed.
+ waitForStart();
+
+ // loop and read the RGB and distance data.
+ // Note we use opModeIsActive() as our loop condition because it is an interruptible method.
+ while (opModeIsActive()) {
+ // convert the RGB values to HSV values.
+ // multiply by the SCALE_FACTOR.
+ // then cast it back to int (SCALE_FACTOR is a double)
+ Color.RGBToHSV((int) (sensorColor.red() * SCALE_FACTOR),
+ (int) (sensorColor.green() * SCALE_FACTOR),
+ (int) (sensorColor.blue() * SCALE_FACTOR),
+ hsvValues);
+
+ // send the info back to driver station using telemetry function.
+ telemetry.addData("Distance (cm)",
+ String.format(Locale.US, "%.02f", sensorDistance.getDistance(DistanceUnit.CM)));
+ telemetry.addData("Alpha", sensorColor.alpha());
+ telemetry.addData("Red ", sensorColor.red());
+ telemetry.addData("Green", sensorColor.green());
+ telemetry.addData("Blue ", sensorColor.blue());
+ telemetry.addData("Hue", hsvValues[0]);
+
+ // change the background color to match the color detected by the RGB sensor.
+ // pass a reference to the hue, saturation, and value array as an argument
+ // to the HSVToColor method.
+ relativeLayout.post(new Runnable() {
+ public void run() {
+ relativeLayout.setBackgroundColor(Color.HSVToColor(0xff, values));
+ }
+ });
+
+ telemetry.update();
+ }
+ }
+}
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java
index 13481f255c5..9a94f5418f6 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java
@@ -31,10 +31,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
package org.firstinspires.ftc.robotcontroller.internal;
-import com.google.blocks.ftcrobotcontroller.runtime.BlocksOpMode;
import com.qualcomm.robotcore.eventloop.opmode.OpModeManager;
import com.qualcomm.robotcore.eventloop.opmode.OpModeRegister;
-import com.qualcomm.robotcore.eventloop.opmode.AnnotatedOpModeRegistrar;
+
import org.firstinspires.ftc.robotcontroller.external.samples.ConceptNullOp;
/**
@@ -64,16 +63,6 @@ public class FtcOpModeRegister implements OpModeRegister {
*/
public void register(OpModeManager manager) {
- /**
- * Register OpModes implemented in the Blocks visual programming language.
- */
- BlocksOpMode.registerAll(manager);
-
- /**
- * Register OpModes that use the annotation-based registration mechanism.
- */
- AnnotatedOpModeRegistrar.register(manager);
-
/**
* Any manual OpMode class registrations should go here.
*/
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcRobotControllerActivity.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcRobotControllerActivity.java
index c0e13f7c054..a1864a850d2 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcRobotControllerActivity.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcRobotControllerActivity.java
@@ -37,6 +37,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.hardware.usb.UsbDevice;
@@ -45,6 +46,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -57,6 +59,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import com.google.blocks.ftcrobotcontroller.BlocksActivity;
import com.google.blocks.ftcrobotcontroller.ProgrammingModeActivity;
import com.google.blocks.ftcrobotcontroller.ProgrammingModeControllerImpl;
+import com.google.blocks.ftcrobotcontroller.ProgrammingWebHandlers;
import com.google.blocks.ftcrobotcontroller.runtime.BlocksOpMode;
import com.qualcomm.ftccommon.AboutActivity;
import com.qualcomm.ftccommon.ClassManagerFactory;
@@ -66,6 +69,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import com.qualcomm.ftccommon.FtcRobotControllerService.FtcRobotControllerBinder;
import com.qualcomm.ftccommon.FtcRobotControllerSettingsActivity;
import com.qualcomm.ftccommon.LaunchActivityConstantsList;
+import com.qualcomm.ftccommon.LaunchActivityConstantsList.RequestCode;
import com.qualcomm.ftccommon.ProgrammingModeController;
import com.qualcomm.ftccommon.Restarter;
import com.qualcomm.ftccommon.UpdateUI;
@@ -75,10 +79,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import com.qualcomm.ftccommon.configuration.RobotConfigFileManager;
import com.qualcomm.ftcrobotcontroller.R;
import com.qualcomm.hardware.HardwareFactory;
+import com.qualcomm.robotcore.eventloop.EventLoopManager;
+import com.qualcomm.robotcore.eventloop.opmode.FtcRobotControllerServiceState;
import com.qualcomm.robotcore.eventloop.opmode.OpModeRegister;
import com.qualcomm.robotcore.hardware.configuration.LynxConstants;
import com.qualcomm.robotcore.hardware.configuration.Utility;
-import com.qualcomm.robotcore.robocol.PeerAppRobotController;
import com.qualcomm.robotcore.util.Dimmer;
import com.qualcomm.robotcore.util.ImmersiveMode;
import com.qualcomm.robotcore.util.RobotLog;
@@ -87,21 +92,31 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import com.qualcomm.robotcore.wifi.WifiDirectAssistant;
import org.firstinspires.ftc.ftccommon.external.SoundPlayingRobotMonitor;
-import org.firstinspires.ftc.robotcore.internal.AppUtil;
-import org.firstinspires.ftc.robotcore.internal.DragonboardLynxDragonboardIsPresentPin;
-import org.firstinspires.ftc.robotcore.internal.PreferencesHelper;
-import org.firstinspires.ftc.robotcore.internal.UILocation;
+import org.firstinspires.ftc.ftccommon.internal.FtcRobotControllerWatchdogService;
+import org.firstinspires.ftc.ftccommon.internal.ProgramAndManageActivity;
+import org.firstinspires.ftc.robotcore.internal.hardware.DragonboardLynxDragonboardIsPresentPin;
import org.firstinspires.ftc.robotcore.internal.network.DeviceNameManager;
import org.firstinspires.ftc.robotcore.internal.network.PreferenceRemoterRC;
import org.firstinspires.ftc.robotcore.internal.network.StartResult;
+import org.firstinspires.ftc.robotcore.internal.system.AppUtil;
+import org.firstinspires.ftc.robotcore.internal.system.Assert;
+import org.firstinspires.ftc.robotcore.internal.system.PreferencesHelper;
+import org.firstinspires.ftc.robotcore.internal.system.ServiceController;
+import org.firstinspires.ftc.robotcore.internal.ui.LocalByRefIntentExtraHolder;
+import org.firstinspires.ftc.robotcore.internal.ui.ThemedActivity;
+import org.firstinspires.ftc.robotcore.internal.ui.UILocation;
+import org.firstinspires.ftc.robotcore.internal.webserver.RobotControllerWebInfo;
+import org.firstinspires.ftc.robotcore.internal.webserver.WebServer;
import org.firstinspires.inspection.RcInspectionActivity;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
-public class FtcRobotControllerActivity extends Activity {
-
+@SuppressWarnings("WeakerAccess")
+public class FtcRobotControllerActivity extends Activity
+ {
public static final String TAG = "RCActivity";
+ public String getTag() { return TAG; }
private static final int REQUEST_CONFIG_WIFI_CHANNEL = 1;
private static final int NUM_GAMEPADS = 2;
@@ -109,15 +124,16 @@ public class FtcRobotControllerActivity extends Activity {
protected WifiManager.WifiLock wifiLock;
protected RobotConfigFileManager cfgFileMgr;
+ protected ProgrammingWebHandlers programmingWebHandlers;
protected ProgrammingModeController programmingModeController;
protected UpdateUI.Callback callback;
protected Context context;
protected Utility utility;
- protected AppUtil appUtil = AppUtil.getInstance();
protected StartResult deviceNameManagerStartResult = new StartResult();
protected StartResult prefRemoterStartResult = new StartResult();
protected PreferencesHelper preferencesHelper;
+ protected final SharedPreferencesListener sharedPreferencesListener = new SharedPreferencesListener();
protected ImageButton buttonMenu;
protected TextView textDeviceName;
@@ -200,12 +216,15 @@ protected void passReceivedUsbAttachmentsToEventLoop() {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- RobotLog.writeLogcatToDisk();
RobotLog.vv(TAG, "onCreate()");
+ ThemedActivity.appAppThemeToActivity(getTag(), this); // do this way instead of inherit to help AppInventor
+
+ Assert.assertTrue(FtcRobotControllerWatchdogService.isFtcRobotControllerActivity(AppUtil.getInstance().getRootActivity()));
+ Assert.assertTrue(AppUtil.getInstance().isRobotController());
// Quick check: should we pretend we're not here, and so allow the Lynx to operate as
// a stand-alone USB-connected module?
- if (LynxConstants.isDragonboardWithEmbeddedLynxModule()) {
+ if (LynxConstants.isRevControlHub()) {
if (LynxConstants.disableDragonboard()) {
// Double-sure check that the Lynx Module can operate over USB, etc, then get out of Dodge
RobotLog.vv(TAG, "disabling Dragonboard and exiting robot controller");
@@ -220,7 +239,6 @@ protected void onCreate(Bundle savedInstanceState) {
context = this;
utility = new Utility(this);
- appUtil.setThisApp(new PeerAppRobotController(context));
DeviceNameManager.getInstance().start(deviceNameManagerStartResult);
PreferenceRemoterRC.getInstance().start(prefRemoterStartResult);
@@ -231,6 +249,7 @@ protected void onCreate(Bundle savedInstanceState) {
preferencesHelper = new PreferencesHelper(TAG, context);
preferencesHelper.writeBooleanPrefIfDifferent(context.getString(R.string.pref_rc_connected), true);
+ preferencesHelper.getSharedPreferences().registerOnSharedPreferenceChangeListener(sharedPreferencesListener);
entireScreenLayout = (LinearLayout) findViewById(R.id.entire_screen);
buttonMenu = (ImageButton) findViewById(R.id.menu_buttons);
@@ -243,7 +262,8 @@ public void onClick(View v) {
BlocksOpMode.setActivityAndWebView(this, (WebView) findViewById(R.id.webViewBlocksRuntime));
- ClassManagerFactory.processClasses();
+ ClassManagerFactory.registerFilters();
+ ClassManagerFactory.processAllClasses();
cfgFileMgr = new RobotConfigFileManager(this);
// Clean up 'dirty' status after a possible crash
@@ -264,15 +284,16 @@ public void onClick(View v) {
dimmer = new Dimmer(this);
dimmer.longBright();
+ programmingWebHandlers = new ProgrammingWebHandlers();
programmingModeController = new ProgrammingModeControllerImpl(
- this, (TextView) findViewById(R.id.textRemoteProgrammingMode));
+ this, (TextView) findViewById(R.id.textRemoteProgrammingMode), programmingWebHandlers);
updateUI = createUpdateUI();
callback = createUICallback(updateUI);
- PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
+ PreferenceManager.setDefaultValues(this, R.xml.app_settings, false);
- WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "");
hittingMenuButtonBrightensScreen();
@@ -280,7 +301,7 @@ public void onClick(View v) {
wifiLock.acquire();
callback.networkConnectionUpdate(WifiDirectAssistant.Event.DISCONNECTED);
readNetworkType();
- startWatchdogService();
+ ServiceController.startService(FtcRobotControllerWatchdogService.class);
bindToService();
logPackageVersions();
}
@@ -328,7 +349,7 @@ protected void onResume() {
}
@Override
- public void onPause() {
+ protected void onPause() {
super.onPause();
RobotLog.vv(TAG, "onPause()");
if (programmingModeController.isActive()) {
@@ -345,7 +366,7 @@ protected void onStop() {
}
@Override
- public void onDestroy() {
+ protected void onDestroy() {
super.onDestroy();
RobotLog.vv(TAG, "onDestroy()");
@@ -356,8 +377,11 @@ public void onDestroy() {
DeviceNameManager.getInstance().stop(deviceNameManagerStartResult);
unbindFromService();
- stopWatchdogService();
+ // If the app manually (?) is stopped, then we don't need the auto-starting function (?)
+ ServiceController.stopService(FtcRobotControllerWatchdogService.class);
wifiLock.release();
+
+ preferencesHelper.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener);
RobotLog.cancelWriteLogcatToDisk();
}
@@ -368,35 +392,6 @@ protected void bindToService() {
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
- protected Intent getWatchdogServiceIntent() {
- return new Intent(context, FtcRobotControllerWatchdogService.class);
- }
-
- protected void startWatchdogService() {
- RobotLog.vv(TAG, "startWatchdogService()");
- Intent intent = getWatchdogServiceIntent();
- try {
- ComponentName componentName = context.startService(intent);
- if (componentName == null) {
- RobotLog.ee(TAG, "watchdog service does not exist");
- } else {
- RobotLog.vv(TAG, "watchdog service = %s", componentName);
- }
- } catch (SecurityException e) {
- RobotLog.logExceptionHeader(TAG, e, "unable to start watchdog service");
- }
- }
-
- protected void stopWatchdogService() {
- RobotLog.vv(TAG, "stopWatchdogService()");
- Intent intent = getWatchdogServiceIntent();
- try {
- context.stopService(intent);
- } catch (SecurityException e) {
- RobotLog.logExceptionHeader(TAG, e, "unable to stop watchdog service");
- }
- }
-
protected void unbindFromService() {
if (controllerService != null) {
unbindService(connection);
@@ -422,12 +417,10 @@ protected void readNetworkType() {
// Moreover, the non-Wifi-Direct networking is end-of-life, so the simplest and most robust
// (e.g.: no one can screw things up by messing with the contents of the config file) fix is
// to do away with configuration file entirely.
-
networkType = NetworkType.WIFIDIRECT;
- programmingModeController.setCurrentNetworkType(networkType);
- // update the preferences
- preferencesHelper.writeStringPrefIfDifferent(context.getString(com.qualcomm.robotcore.R.string.pref_network_connection_type), networkType.toString());
+ // update the app_settings
+ preferencesHelper.writeStringPrefIfDifferent(context.getString(R.string.pref_network_connection_type), networkType.toString());
}
@Override
@@ -460,21 +453,28 @@ public boolean onOptionsItemSelected(MenuItem item) {
if (id == R.id.action_programming_mode) {
if (cfgFileMgr.getActiveConfig().isNoConfig()) {
// Tell the user they must configure the robot before starting programming mode.
+ // TODO: as we are no longer truly 'modal' this warning should be adapted
AppUtil.getInstance().showToast(UILocation.BOTH, context, context.getString(R.string.toastConfigureRobotBeforeProgrammingMode));
} else {
- Intent programmingModeIntent = new Intent(ProgrammingModeActivity.launchIntent);
+ Intent programmingModeIntent = new Intent(AppUtil.getDefContext(), ProgrammingModeActivity.class);
programmingModeIntent.putExtra(
- LaunchActivityConstantsList.PROGRAMMING_MODE_ACTIVITY_NETWORK_TYPE, networkType);
+ LaunchActivityConstantsList.PROGRAMMING_MODE_ACTIVITY_PROGRAMMING_WEB_HANDLERS,
+ new LocalByRefIntentExtraHolder(programmingWebHandlers));
startActivity(programmingModeIntent);
}
return true;
+ } else if (id == R.id.action_program_and_manage) {
+ Intent programmingModeIntent = new Intent(AppUtil.getDefContext(), ProgramAndManageActivity.class);
+ RobotControllerWebInfo webInfo = programmingWebHandlers.getWebServer().getConnectionInformation();
+ programmingModeIntent.putExtra(LaunchActivityConstantsList.RC_WEB_INFO, webInfo.toJson());
+ startActivity(programmingModeIntent);
} else if (id == R.id.action_inspection_mode) {
- Intent inspectionModeIntent = new Intent(RcInspectionActivity.rcLaunchIntent);
+ Intent inspectionModeIntent = new Intent(AppUtil.getDefContext(), RcInspectionActivity.class);
startActivity(inspectionModeIntent);
return true;
}
else if (id == R.id.action_blocks) {
- Intent blocksIntent = new Intent(BlocksActivity.launchIntent);
+ Intent blocksIntent = new Intent(AppUtil.getDefContext(), BlocksActivity.class);
startActivity(blocksIntent);
return true;
}
@@ -486,17 +486,18 @@ else if (id == R.id.action_restart_robot) {
}
else if (id == R.id.action_configure_robot) {
EditParameters parameters = new EditParameters();
- Intent intentConfigure = new Intent(FtcLoadFileActivity.launchIntent);
+ Intent intentConfigure = new Intent(AppUtil.getDefContext(), FtcLoadFileActivity.class);
parameters.putIntent(intentConfigure);
- startActivityForResult(intentConfigure, LaunchActivityConstantsList.FTC_CONFIGURE_REQUEST_CODE_ROBOT_CONTROLLER);
+ startActivityForResult(intentConfigure, RequestCode.CONFIGURE_ROBOT_CONTROLLER.ordinal());
}
else if (id == R.id.action_settings) {
- Intent settingsIntent = new Intent(FtcRobotControllerSettingsActivity.launchIntent);
- startActivityForResult(settingsIntent, LaunchActivityConstantsList.FTC_CONFIGURE_REQUEST_CODE_ROBOT_CONTROLLER);
+ // historical: this once erroneously used FTC_CONFIGURE_REQUEST_CODE_ROBOT_CONTROLLER
+ Intent settingsIntent = new Intent(AppUtil.getDefContext(), FtcRobotControllerSettingsActivity.class);
+ startActivityForResult(settingsIntent, RequestCode.SETTINGS_ROBOT_CONTROLLER.ordinal());
return true;
}
else if (id == R.id.action_about) {
- Intent intent = new Intent(AboutActivity.launchIntent);
+ Intent intent = new Intent(AppUtil.getDefContext(), AboutActivity.class);
intent.putExtra(LaunchActivityConstantsList.ABOUT_ACTIVITY_CONNECTION_TYPE, networkType);
startActivity(intent);
return true;
@@ -522,18 +523,31 @@ protected void onActivityResult(int request, int result, Intent intent) {
AppUtil.getInstance().showToast(UILocation.BOTH, context, context.getString(R.string.toastWifiConfigurationComplete));
}
}
- if (request == LaunchActivityConstantsList.FTC_CONFIGURE_REQUEST_CODE_ROBOT_CONTROLLER) {
+ // was some historical confusion about launch codes here, so we err safely
+ if (request == RequestCode.CONFIGURE_ROBOT_CONTROLLER.ordinal() || request == RequestCode.SETTINGS_ROBOT_CONTROLLER.ordinal()) {
// We always do a refresh, whether it was a cancel or an OK, for robustness
cfgFileMgr.getActiveConfigAndUpdateUI();
}
}
- public void onServiceBind(FtcRobotControllerService service) {
+ public void onServiceBind(final FtcRobotControllerService service) {
RobotLog.vv(FtcRobotControllerService.TAG, "%s.controllerService=bound", TAG);
controllerService = service;
updateUI.setControllerService(controllerService);
updateUIAndRequestRobotSetup();
+ programmingWebHandlers.setState(new FtcRobotControllerServiceState() {
+ @NonNull
+ @Override
+ public WebServer getWebServer() {
+ return service.getWebServer();
+ }
+
+ @Override
+ public EventLoopManager getEventLoopManager() {
+ return service.getRobot().eventLoopManager;
+ }
+ });
}
private void updateUIAndRequestRobotSetup() {
@@ -559,8 +573,9 @@ private void requestRobotSetup() {
}
factory = hardwareFactory;
- eventLoop = new FtcEventLoop(factory, createOpModeRegister(), callback, this, programmingModeController);
- FtcEventLoopIdle idleLoop = new FtcEventLoopIdle(factory, callback, this, programmingModeController);
+ OpModeRegister userOpModeRegister = createOpModeRegister();
+ eventLoop = new FtcEventLoop(factory, userOpModeRegister, callback, this, programmingModeController);
+ FtcEventLoopIdle idleLoop = new FtcEventLoopIdle(factory, userOpModeRegister, callback, this, programmingModeController);
controllerService.setCallback(callback);
controllerService.setupRobot(eventLoop, idleLoop);
@@ -577,12 +592,12 @@ private void shutdownRobot() {
}
private void requestRobotRestart() {
- AppUtil.getInstance().showToast(UILocation.BOTH, AppUtil.getDefContext().getString(com.qualcomm.ftccommon.R.string.toastRestartingRobot));
+ AppUtil.getInstance().showToast(UILocation.BOTH, AppUtil.getDefContext().getString(R.string.toastRestartingRobot));
//
shutdownRobot();
requestRobotSetup();
//
- AppUtil.getInstance().showToast(UILocation.BOTH, AppUtil.getDefContext().getString(com.qualcomm.ftccommon.R.string.toastRestartRobotComplete));
+ AppUtil.getInstance().showToast(UILocation.BOTH, AppUtil.getDefContext().getString(R.string.toastRestartRobotComplete));
}
protected void hittingMenuButtonBrightensScreen() {
@@ -598,4 +613,12 @@ public void onMenuVisibilityChanged(boolean isVisible) {
});
}
}
+
+ protected class SharedPreferencesListener implements SharedPreferences.OnSharedPreferenceChangeListener {
+ @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(context.getString(R.string.pref_app_theme))) {
+ ThemedActivity.restartForAppThemeChange(getTag(), getString(R.string.appThemeChangeRestartNotifyRC));
+ }
+ }
+ }
}
diff --git a/FtcRobotController/src/main/res/layout/activity_ftc_controller.xml b/FtcRobotController/src/main/res/layout/activity_ftc_controller.xml
index d1f901467bb..b47f9c24782 100644
--- a/FtcRobotController/src/main/res/layout/activity_ftc_controller.xml
+++ b/FtcRobotController/src/main/res/layout/activity_ftc_controller.xml
@@ -35,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ xmlns:style="http://schemas.android.com/apk/res-auto"
tools:context="org.firstinspires.ftc.robotcontroller.internal.FtcRobotControllerActivity"
android:focusable="true"
android:id="@+id/entire_screen"
@@ -45,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
android:id="@+id/top_bar"
android:layout_width="fill_parent"
android:layout_height="80dp"
- android:background="@color/black">
+ android:background="@color/background_black">
@@ -71,7 +72,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_menu"
- android:background="@color/black"
+ android:background="@android:color/transparent"
android:padding="15dp"
android:adjustViewBounds="true"
android:layout_alignParentEnd="true"
@@ -136,14 +137,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
allow for a bigger camera monitor view in the common case when the
error is not in fact present
-->
-
+ android:textColor="?attr/textMediumDark" />
@@ -163,13 +163,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
android:visibility="invisible"
android:text="" />
+
-
+
+
+
+
diff --git a/FtcRobotController/src/main/res/values/strings.xml b/FtcRobotController/src/main/res/values/strings.xml
index 240e7121312..d1485319c4c 100644
--- a/FtcRobotController/src/main/res/values/strings.xml
+++ b/FtcRobotController/src/main/res/values/strings.xml
@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Self Inspect
Programming Mode
+ Program & Manage
Blocks
Settings
Restart Robot
@@ -55,4 +56,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Restarting Robot
You must Configure Robot before starting Programming Mode.
+
+
+ - @style/AppThemeRedRC
+ - @style/AppThemeGreenRC
+ - @style/AppThemeBlueRC
+ - @style/AppThemePurpleRC
+ - @style/AppThemeOrangeRC
+ - @style/AppThemeTealRC
+
+
+ @string/packageNameRobotController
+
diff --git a/FtcRobotController/src/main/res/values/styles.xml b/FtcRobotController/src/main/res/values/styles.xml
index c3f7c2f5bd1..07689c03896 100644
--- a/FtcRobotController/src/main/res/values/styles.xml
+++ b/FtcRobotController/src/main/res/values/styles.xml
@@ -1,71 +1,23 @@
-
-
+
+
-
-
-
-
+
+
+
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/FtcRobotController/src/main/res/xml/app_settings.xml b/FtcRobotController/src/main/res/xml/app_settings.xml
new file mode 100644
index 00000000000..adc3223afe8
--- /dev/null
+++ b/FtcRobotController/src/main/res/xml/app_settings.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.common.gradle b/build.common.gradle
index e22d42a0148..59f218ac3cd 100644
--- a/build.common.gradle
+++ b/build.common.gradle
@@ -22,7 +22,7 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 23
- buildToolsVersion '23.0.3'
+ buildToolsVersion '25.0.3'
signingConfigs {
debug {
diff --git a/build.gradle b/build.gradle
index 5451ba0c087..8a1696fa669 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,7 +8,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.3'
+ classpath 'com.android.tools.build:gradle:2.3.1'
}
}
diff --git a/doc/apk/FtcDriverStation-release.apk b/doc/apk/FtcDriverStation-release.apk
index c295ad54002..e1a0a773b7a 100644
Binary files a/doc/apk/FtcDriverStation-release.apk and b/doc/apk/FtcDriverStation-release.apk differ
diff --git a/doc/apk/FtcRobotController-release.apk b/doc/apk/FtcRobotController-release.apk
index e1144deef90..4a124a1b24a 100644
Binary files a/doc/apk/FtcRobotController-release.apk and b/doc/apk/FtcRobotController-release.apk differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e892e011575..bd4dbf657c0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Mon Aug 22 11:38:56 EDT 2016
+#Tue Apr 04 22:12:45 PDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip
+
diff --git a/libs/Blocks-release-sources.jar b/libs/Blocks-release-sources.jar
index 5993bc0a79d..8602cbf280c 100644
Binary files a/libs/Blocks-release-sources.jar and b/libs/Blocks-release-sources.jar differ
diff --git a/libs/Blocks-release.aar b/libs/Blocks-release.aar
index 100f8f6424f..3957644f170 100644
Binary files a/libs/Blocks-release.aar and b/libs/Blocks-release.aar differ
diff --git a/libs/FtcCommon-release-sources.jar b/libs/FtcCommon-release-sources.jar
index cef75238e8e..25175c79cc7 100644
Binary files a/libs/FtcCommon-release-sources.jar and b/libs/FtcCommon-release-sources.jar differ
diff --git a/libs/FtcCommon-release.aar b/libs/FtcCommon-release.aar
index 4e567391904..a824c74fbe7 100644
Binary files a/libs/FtcCommon-release.aar and b/libs/FtcCommon-release.aar differ
diff --git a/libs/Hardware-release-sources.jar b/libs/Hardware-release-sources.jar
index 2f732d0b1dd..ec10f2395ec 100644
Binary files a/libs/Hardware-release-sources.jar and b/libs/Hardware-release-sources.jar differ
diff --git a/libs/Hardware-release.aar b/libs/Hardware-release.aar
index db05b61acee..8ee5acd2fb3 100644
Binary files a/libs/Hardware-release.aar and b/libs/Hardware-release.aar differ
diff --git a/libs/Inspection-release-sources.jar b/libs/Inspection-release-sources.jar
index 2dc74df1a1a..37981c88837 100644
Binary files a/libs/Inspection-release-sources.jar and b/libs/Inspection-release-sources.jar differ
diff --git a/libs/Inspection-release.aar b/libs/Inspection-release.aar
index d676fc01456..eefd3d78ff8 100644
Binary files a/libs/Inspection-release.aar and b/libs/Inspection-release.aar differ
diff --git a/libs/RobotCore-release-sources.jar b/libs/RobotCore-release-sources.jar
index 05adfe4a893..ca546679779 100644
Binary files a/libs/RobotCore-release-sources.jar and b/libs/RobotCore-release-sources.jar differ
diff --git a/libs/RobotCore-release.aar b/libs/RobotCore-release.aar
index ee766b3527f..88a9d85e167 100644
Binary files a/libs/RobotCore-release.aar and b/libs/RobotCore-release.aar differ