FPII-2286: Dynamically compute the offset compensation
Compute the offset compensation based on the current calibration and
on the values read.
Re-factor the app globally and bump version number to 2.0 (20099).
Change-Id: Ic43456ae85b72f76804767fd54111cc22191d5b3
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..816e37e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,25 @@
+The app version (a.k.a Version Code) is based on the following scheme:
+
+* Major version number
+* Minor version number
+* Release status number (snapshot/release candidate/public release)
+
+The rules are as follow:
+
+* The major version uses two digits
+* The minor version uses two digits
+* The release status uses two digits
+* The major version should be bumped when introducing new features
+* The minor version should be bumped whenever there is a (simple/hot) fix
+* The release status must be 0 while developing (snapshot)
+* The release status must be in [1;98] while testing releases (release candidate)
+* The release status must be 99 for a public release
+
+The readable app version (a.k.a Version Name) is based on the app version with the following schemes:
+
+* Snapshots are named after <major version>.<minor version>-SNAPSHOT
+* Release candidates are named after <major version>.<minor version>-RC<release status>
+* Public releases are named after <major version>.<minor version>
+
+TODO: implement an automatic translation from app version to readable app version
+TODO: implement an automatic version bumping task when pushing/merging/integrating features/fixes
diff --git a/app/build.gradle b/app/build.gradle
index 770ac31..b7fad15 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,14 +1,14 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 23
+ compileSdkVersion 22
buildToolsVersion '22.0.1'
defaultConfig {
applicationId "com.fairphone.psensor"
minSdkVersion 22
targetSdkVersion 22
- versionCode 1
- versionName "1.0"
+ versionCode 20099
+ versionName "2.0"
}
buildTypes {
release {
@@ -25,6 +25,6 @@
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:23.4.0'
- compile 'com.android.support:support-v13:24.1.0'
+ compile 'com.android.support:support-v13:22.2.1'
+ compile 'com.android.support:support-v4:22.2.1'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ca67335..0d76418 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,12 +3,12 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.fairphone.psensor"
android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0">
+ android:versionCode="20099"
+ android:versionName="2.0">
<uses-sdk
- android:minSdkVersion="17"
- android:targetSdkVersion="21" />
+ android:minSdkVersion="22"
+ android:targetSdkVersion="22" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
@@ -21,7 +21,8 @@
<application
android:allowBackup="true"
android:label="@string/app_name"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ android:icon="@mipmap/ic_launcher_settings">
<activity android:name="com.fairphone.psensor.UpdateFinalizerActivity"
android:enabled="false"
diff --git a/app/src/main/java/com/fairphone/psensor/BootUpReceiver.java b/app/src/main/java/com/fairphone/psensor/BootUpReceiver.java
index 62e4249..ffe9fcf 100644
--- a/app/src/main/java/com/fairphone/psensor/BootUpReceiver.java
+++ b/app/src/main/java/com/fairphone/psensor/BootUpReceiver.java
@@ -6,6 +6,7 @@
import android.content.Intent;
import android.provider.Settings;
+import com.fairphone.psensor.helpers.CalibrationStatusHelper;
public class BootUpReceiver extends BroadcastReceiver {
@@ -19,6 +20,10 @@
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
UpdateFinalizerService.startActionBootUp(context);
+
+ if (CalibrationStatusHelper.isCalibrationPending(context)) {
+ CalibrationStatusHelper.setCalibrationCompleted(context);
+ }
}
if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
UpdateFinalizerService.startActionShutdown(context);
diff --git a/app/src/main/java/com/fairphone/psensor/CalibrationActivity.java b/app/src/main/java/com/fairphone/psensor/CalibrationActivity.java
index 7f874fa..2ad977f 100644
--- a/app/src/main/java/com/fairphone/psensor/CalibrationActivity.java
+++ b/app/src/main/java/com/fairphone/psensor/CalibrationActivity.java
@@ -1,9 +1,11 @@
-
package com.fairphone.psensor;
import android.app.Activity;
+import android.app.DialogFragment;
+import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -15,294 +17,356 @@
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
-import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.ViewFlipper;
import com.fairphone.psensor.CalibrationContract.CalibrationData;
+import com.fairphone.psensor.fragments.IncompatibleDeviceDialog;
+import com.fairphone.psensor.helpers.CalibrationStatusHelper;
+import com.fairphone.psensor.helpers.ProximitySensorHelper;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
+import java.util.Locale;
/**
- * 1. Hint user block sensor and read value. if less than 230, hint and wait confirm. <BR>
- * 2. Hint user unblock sensor and read value. if greater than 96, hint and wait confirm. <BR>
- * 3. Use the value of unblock to do the calibration. value+30 as far, value+60 as near. <BR>
- * 4. Write far and near value to /persist/sns.reg binary file. <BR>
- * 5. The file of sns.reg content as "0000100: 0a3c 0000 <near> <far> 6400 6400 01c0 0000" <BR>
+ * Activity to start the calibration process.<br>
+ * <br>
+ * The calibration steps are:
+ * <ol>
+ * <li>Ask for a blocked sensor and read the (blocked) value.</li>
+ * <li>Ask for a non-blocked sensor and read the (non-blocked) value.</li>
+ * <li>Compute a new calibration (near and far threshold as well as the offset compensation) and persist it into the
+ * memory.</li>
+ * </ol>
+ * <br>
+ * The offset compensation is -was- 0 out of factory and could cause issues because certain devices require a higher
+ * compensation.<br>
+ * <br>
+ * The dynamic offset compensation is computed from the non-blocked value read at step 2.<br>
+ * The rules are as follow:
+ * <ol>
+ * <li>The read value is reduced by approx. 32 (sensor units) for each offset compensation increment (from the
+ * specification).</li>
+ * <li>According to the vendor, the value read must be above 0 when non-blocked, so we use the offset value directly
+ * lower than floor("value read"/32) to be on the safe side.</li>
+ * <li>This also allows to take into account a dirty current state. The non-blocked value then belongs to [32;63] in
+ * the current conditions.</li>
+ * <li>If the value read is already 0, we lower the persisted offset by 2 to reach a similar non-blocked range than
+ * above.</li>
+ * <li>The proximity sensor offset compensation belongs to [{@link ProximitySensorConfiguration#MIN_OFFSET_COMPENSATION}, {@link ProximitySensorConfiguration#MAX_OFFSET_COMPENSATION}].</li>
+ * </ol>
*/
-public class CalibrationActivity extends Activity {
+public class CalibrationActivity extends Activity implements IncompatibleDeviceDialog.IncompatibleDeviceDialogListener {
private static final String TAG = CalibrationActivity.class.getSimpleName();
- private static final String CALIBRATION_FILE = "/persist/sns.reg";
- private static final String CMD = "senread";
- private static final String RESULT_PREFIX = "[RESULT]";
- private static final int DEFAULT_OFFSET = 0x01;
- protected static final int OFFSET_FAR = 30;
- protected static final int OFFSET_NEAR = 30;
- protected static final int READ_MIN_LIMIT = 0;
- protected static final int READ_MAX_LIMIT = 255;
- protected static final int BLOCK_LIMIT = 235;
- protected static final int UNBLOCK_LIMIT = 180;
- private static final int SEEK_NEAR = 0x00000100 + 4;
- private static final int SEEK_FAR = 0x00000100 + 6;
- private static final int SEEK_OFFSET = 0x00000128;
+ /* Calibration step status */
+ private static final int STEP_CURRENT = 0;
+ private static final int STEP_IN_PROGRESS = 1;
+ private static final int STEP_ERROR = 2;
+ private static final int STEP_OK = 3;
- private static final int STATE_START = 0;
- private static final int STATE_BLOCK = 11;
- private static final int STATE_BLOCK_READ = 12;
- private static final int STATE_BLOCK_WARN = 13;
- private static final int STATE_UNBLOCK = 21;
- private static final int STATE_UNBLOCK_READ = 22;
- private static final int STATE_UNBLOCK_WARN = 23;
- private static final int STATE_CAL = 3;
- private static final int STATE_SUCCESS = 4;
- private static final int STATE_FAIL = 5;
- private static final int STATE_FAIL_STEP_2 = 6;
+ /**
+ * Value to compute the near threshold from the blocked value (in sensor units).
+ */
+ public static final int NEAR_THRESHOLD_FROM_BLOCKED_VALUE = 30;
+ /**
+ * Value to compute the far threshold from the near threshold (in sensor units).
+ */
+ public static final int FAR_THRESHOLD_FROM_NEAR_THRESHOLD = 30;
+ /**
+ * Minimal accepted value for the blocked value (in sensor units).
+ */
+ public static final int BLOCKED_MINIMAL_VALUE = 235;
+ /**
+ * Maximal accepted value for the non-blocked value in relation to the read blocked value (in sensor units).
+ */
+ public static final int NON_BLOCKED_MAXIMAL_VALUE_FROM_BLOCKED_VALUE = 5;
+ /**
+ * Delay to emulate a long calibration (in ms).
+ */
+ public static final int CALIBRATION_DELAY_MS = 3000;
- protected static final int READ_N_TIMES = 3;
- protected static final int READ_DELAY = 500;
+ private ProximitySensorConfiguration mPersistedConfiguration;
+ private ProximitySensorConfiguration mCalibratedConfiguration;
+
+ private int mBlockedValue;
+ private int mNonBlockedValue;
private Handler mHandler;
- private TextView mStep1;
- private TextView mText1;
- private Button mButton1;
- private TextView mStep2;
- private TextView mText2;
- private Button mButton2;
- private TextView mStep3;
- private TextView mText3;
- private Button mButton3;
-
- private int mPersistedDataFar;
- private int mPersistedDataNear;
- private int mPersistedDataOffset;
- private int mDataFar;
- private int mDataNear;
- private int mDataOffset;
- private int mState = STATE_START;
private ViewFlipper mFlipper;
private View mViewStep1;
private View mViewStep2;
private View mViewStep3;
- private ProgressBar mProgressBar1;
- private ProgressBar mProgressBar2;
+ private final View.OnClickListener actionReboot = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ powerManager.reboot(null);
+ }
+
+ };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getPersistedValues();
-
- mHandler=new Handler();
+ mHandler = new Handler();
setContentView(R.layout.activity_calibration);
- mFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
+ if (!ProximitySensorHelper.canReadProximitySensorValue()) {
+ Log.w(TAG, "Proximity sensor value not read-able, aborting.");
+ showIncompatibleDeviceDialog();
+ } else if (!ProximitySensorConfiguration.canReadFromAndPersistToMemory()) {
+ Log.w(TAG, "Proximity sensor configuration not accessible (R/W), aborting.");
+
+ showIncompatibleDeviceDialog();
+ } else {
+ init();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (CalibrationStatusHelper.isCalibrationPending(this)) {
+ updateCalibrationStepView(mViewStep3, STEP_CURRENT, R.string.step_3, R.string.msg_calibration_success, -1, actionReboot, R.string.reboot);
+ if (mFlipper.getDisplayedChild() != 2) {
+ mFlipper.setDisplayedChild(2);
+ }
+ } else {
+ reset();
+ }
+ }
+
+ private void init() {
+ mFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
mFlipper.setInAnimation(this, R.anim.slide_in_from_left);
mFlipper.setOutAnimation(this, R.anim.slide_out_to_right);
-
- LayoutInflater inflater = LayoutInflater.from(this);
- mViewStep1 = inflater.inflate(R.layout.view_calibration_step,null);
- mViewStep2 = inflater.inflate(R.layout.view_calibration_step,null);
- mViewStep3 = inflater.inflate(R.layout.view_calibration_step,null);
+ final LayoutInflater inflater = LayoutInflater.from(this);
+ mViewStep1 = inflater.inflate(R.layout.view_calibration_step, mFlipper, false);
+ mViewStep2 = inflater.inflate(R.layout.view_calibration_step, mFlipper, false);
+ mViewStep3 = inflater.inflate(R.layout.view_calibration_step, mFlipper, false);
mFlipper.addView(mViewStep1);
mFlipper.addView(mViewStep2);
mFlipper.addView(mViewStep3);
-
-
- mStep1 = (TextView) mViewStep1.findViewById(R.id.textview_heading);
- mText1 = (TextView) mViewStep1.findViewById(R.id.maintext);
- mButton1 = (Button) mViewStep1.findViewById(R.id.button);
- mProgressBar1 = (ProgressBar) mViewStep1.findViewById(R.id.progressBar);
- mProgressBar1.setVisibility(View.INVISIBLE);
-
- mButton1.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- changeState(STATE_BLOCK_READ);
- }
- });
- mStep2 = (TextView) mViewStep2.findViewById(R.id.textview_heading);
- mText2 = (TextView) mViewStep2.findViewById(R.id.maintext);
- mButton2 = (Button) mViewStep2.findViewById(R.id.button);
- mStep2.setText(getText(R.string.step_2));
- mText2.setText(getText(R.string.msg_unblock));
- mProgressBar2 = (ProgressBar) mViewStep2.findViewById(R.id.progressBar);
- mProgressBar1.setVisibility(View.INVISIBLE);
-
- mButton2.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- changeState(STATE_UNBLOCK_READ);
- }
- });
- mStep3 = (TextView) mViewStep3.findViewById(R.id.textview_heading);
- mText3 = (TextView) mViewStep3.findViewById(R.id.maintext);
- mButton3 = (Button) mViewStep3.findViewById(R.id.button);
- mStep3.setText(getText(R.string.step_3));
- mText3.setText(getText(R.string.msg_calibration_success));
- mButton3.setText(R.string.reboot);
-
- mButton3.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mFlipper.showNext();
- PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
- powerManager.reboot(null); }
- });
}
- private void changeState(int state) {
- mState = state;
- update();
+ private void reset() {
+ mPersistedConfiguration = ProximitySensorConfiguration.readFromMemory();
+ mCalibratedConfiguration = new ProximitySensorConfiguration();
+
+ updateCalibrationStepView(mViewStep1, STEP_CURRENT, R.string.step_1, R.string.msg_block, -1, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doReadBlockedValue();
+ }
+ }, R.string.next);
+
+ updateCalibrationStepView(mViewStep2, STEP_CURRENT, R.string.step_2, R.string.msg_unblock, -1, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doReadNonBlockedValue();
+ }
+ }, R.string.next);
+
+ updateCalibrationStepView(mViewStep3, STEP_CURRENT, R.string.step_3, R.string.msg_cal, -1, actionReboot, R.string.reboot);
+
+ mFlipper.setDisplayedChild(0);
}
- private void update() {
- switch (mState) {
- case STATE_START:
- changeState(STATE_BLOCK);
+ private void updateCalibrationStepView(View stepView, int viewStatus, int title, int instructions, int errorNotice, View.OnClickListener action, int actionLabel) {
+ final TextView viewTitle = (TextView) stepView.findViewById(R.id.current_step);
+ final TextView viewInstructions = (TextView) stepView.findViewById(R.id.instructions);
+ final TextView viewErrorNotice = (TextView) stepView.findViewById(R.id.error_notice);
+ final View viewInProgress = stepView.findViewById(R.id.progress_bar);
+ final Button buttonAction = (Button) stepView.findViewById(R.id.button);
+
+ switch (viewStatus) {
+ case STEP_CURRENT:
+ viewErrorNotice.setVisibility(View.GONE);
+ viewInProgress.setVisibility(View.GONE);
+
+ buttonAction.setEnabled(true);
break;
- case STATE_BLOCK:
- updateToBlock();
+
+ case STEP_IN_PROGRESS:
+ viewErrorNotice.setVisibility(View.GONE);
+ viewInProgress.setVisibility(View.VISIBLE);
+
+ buttonAction.setEnabled(false);
break;
- case STATE_BLOCK_READ:
- updateToBlockRead();
+
+ case STEP_ERROR:
+ viewErrorNotice.setVisibility(View.VISIBLE);
+ viewInProgress.setVisibility(View.GONE);
+
+ buttonAction.setEnabled(true);
break;
- case STATE_BLOCK_WARN:
- case STATE_UNBLOCK:
- updateToUnblock();
+
+ case STEP_OK:
+ viewErrorNotice.setVisibility(View.GONE);
+ viewInProgress.setVisibility(View.GONE);
+
+ buttonAction.setEnabled(false);
break;
- case STATE_UNBLOCK_READ:
- updateToUnblockRead();
- break;
- case STATE_UNBLOCK_WARN:
- case STATE_CAL:
- updateToCal();
- break;
- case STATE_SUCCESS:
- updateToSuccess();
- break;
- case STATE_FAIL:
- updateToFail();
- break;
- case STATE_FAIL_STEP_2:
- updateToFailStep2();
- break;
+
default:
- break;
+ Log.wtf(TAG, "Unknown calibration step reached: " + viewStatus);
+ }
+
+ if (title != -1) {
+ viewTitle.setText(title);
+ }
+
+ if (instructions != -1) {
+ viewInstructions.setText(instructions);
+ }
+
+ if (errorNotice != -1) {
+ viewErrorNotice.setText(errorNotice);
+ }
+
+ if (action != null) {
+ buttonAction.setOnClickListener(action);
+ }
+
+ if (actionLabel != -1) {
+ buttonAction.setText(actionLabel);
}
}
- private void updateToBlock() {
- //mText1.setText(getString(R.string.msg_block));
- mFlipper.setDisplayedChild(0);
-
- mStep1.setEnabled(true);
- mText1.setEnabled(true);
- mButton1.setEnabled(true);
- mProgressBar1.setVisibility(View.INVISIBLE);
+ private void updateCalibrationStepView(View stepView, int viewStatus, int instructions) {
+ updateCalibrationStepView(stepView, viewStatus, -1, instructions, -1, null, -1);
}
- private void updateToBlockRead() {
- mText1.setText(getString(R.string.msg_reading));
- mButton1.setEnabled(false);
- mProgressBar1.setVisibility(View.VISIBLE);
+ private void updateCalibrationStepView(View stepView, int viewStatus, int instructions, int errorNotice) {
+ updateCalibrationStepView(stepView, viewStatus, -1, instructions, errorNotice, null, -1);
+ }
+
+ private void updateCalibrationStepView(View stepView, int viewStatus, int instructions, int errorNotice, View.OnClickListener action, int actionLabel) {
+ updateCalibrationStepView(stepView, viewStatus, -1, instructions, errorNotice, action, actionLabel);
+ }
+
+ private void doReadBlockedValue() {
+ updateCalibrationStepView(mViewStep1, STEP_IN_PROGRESS, R.string.msg_reading);
+
new Thread(new Runnable() {
@Override
public void run() {
- final int value = read(BLOCK_LIMIT, READ_MAX_LIMIT);
+ final int value = ProximitySensorHelper.read(BLOCKED_MINIMAL_VALUE, ProximitySensorHelper.READ_MAX_LIMIT);
mHandler.post(new Runnable() {
@Override
public void run() {
- Log.d(TAG, "block value = " + String.format("%3d", value) + " (" + String.format("0x%04x", value) + ")");
+ Log.d(TAG, " blocked value = " + String.format(Locale.ENGLISH, "%3d", value));
- if (value >= BLOCK_LIMIT) {
- mDataNear = value - OFFSET_NEAR;
- changeState(STATE_UNBLOCK);
- } else {
- mText1.setText(getString(R.string.msg_fail_block));
- changeState(STATE_FAIL);
- }
+ doSaveBlockedValue(value);
}
});
}
}).start();
}
- private void updateToCal() {
- mText2.setText(R.string.msg_step_success);
- mStep3.setEnabled(true);
- mText3.setEnabled(true);
- mText3.setText(getString(R.string.msg_cal));
- mHandler.post(new Runnable() {
+ private void doSaveBlockedValue(int value) {
+ if (value >= 0) {
+ mBlockedValue = value;
+
+ updateCalibrationStepView(mViewStep1, STEP_OK, R.string.msg_step_success);
+ mFlipper.setDisplayedChild(1);
+ } else {
+ updateCalibrationStepView(mViewStep1, STEP_ERROR, R.string.msg_block, R.string.msg_fail_block);
+ mFlipper.setDisplayedChild(0);
+ }
+ }
+
+ private void doReadNonBlockedValue() {
+ updateCalibrationStepView(mViewStep2, STEP_IN_PROGRESS, R.string.msg_reading);
+
+ new Thread(new Runnable() {
@Override
public void run() {
- if (write()) {
- mText3.setText(getString(R.string.msg_calibration_success));
- mButton3.setEnabled(true);
- changeState(STATE_SUCCESS);
- } else {
- mText3.setText(getString(R.string.msg_fail_write_sns));
- changeState(STATE_FAIL);
+ final int value = ProximitySensorHelper.read(ProximitySensorHelper.READ_MIN_LIMIT, (mBlockedValue - NON_BLOCKED_MAXIMAL_VALUE_FROM_BLOCKED_VALUE));
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(TAG, "non-blocked value = " + String.format(Locale.ENGLISH, "%3d", value));
+
+ doSaveNonBlockedValue(value);
+ }
+ });
+ }
+ }).start();
+ }
+
+ private void doSaveNonBlockedValue(int value) {
+ if (value >= 0) {
+ mNonBlockedValue = value;
+
+ updateCalibrationStepView(mViewStep2, STEP_OK, R.string.msg_step_success);
+ mFlipper.setDisplayedChild(2);
+
+ doCalibrate();
+ } else {
+ updateCalibrationStepView(mViewStep2, STEP_ERROR, R.string.msg_unblock, R.string.msg_fail_unlock);
+ mFlipper.setDisplayedChild(1);
+ }
+ }
+
+ public void doCalibrate() {
+ updateCalibrationStepView(mViewStep3, STEP_IN_PROGRESS, R.string.msg_cal);
+
+ mCalibratedConfiguration.nearThreshold = mBlockedValue - NEAR_THRESHOLD_FROM_BLOCKED_VALUE;
+ mCalibratedConfiguration.farThreshold = mCalibratedConfiguration.nearThreshold - FAR_THRESHOLD_FROM_NEAR_THRESHOLD;
+
+ if (mNonBlockedValue == 0) {
+ mCalibratedConfiguration.offsetCompensation = Math.min(Math.max(mPersistedConfiguration.offsetCompensation - 2, ProximitySensorConfiguration.MIN_OFFSET_COMPENSATION), ProximitySensorConfiguration.MAX_OFFSET_COMPENSATION);
+ Log.d(TAG, "New offset based on current offset only");
+ } else {
+ mCalibratedConfiguration.offsetCompensation = Math.min(Math.max(mPersistedConfiguration.offsetCompensation + (int)Math.floor(mNonBlockedValue / 32) - 1, ProximitySensorConfiguration.MIN_OFFSET_COMPENSATION), ProximitySensorConfiguration.MAX_OFFSET_COMPENSATION);
+ Log.d(TAG, "New offset based on unblock value and current offset");
+ }
+
+ if (mCalibratedConfiguration.persistToMemory()) {
+ storeCalibrationData();
+ CalibrationStatusHelper.setCalibrationSuccessful(this);
+
+ // wait a bit because the calibration is otherwise too fast
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(CALIBRATION_DELAY_MS);
+ } catch (InterruptedException e) {
+ // Log but ignore interruption.
+ Log.e(TAG, e.getMessage());
+ }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ updateCalibrationStepView(mViewStep3, STEP_CURRENT, R.string.msg_calibration_success);
+ mFlipper.setDisplayedChild(2);
+ }
+ });
}
- }
- });
- }
+ }).start();
+ } else {
+ updateCalibrationStepView(mViewStep3, STEP_ERROR, R.string.msg_cal, R.string.msg_fail_write_sns, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ reset();
+ startFairphoneUpdaterActivity();
+ }
+ }, R.string.go_to_updater);
+ }
- private void updateToFail() {
- mButton1.setEnabled(true);
- changeState(STATE_BLOCK);
- }
-
- private void updateToFailStep2() {
- mText2.setText(getString(R.string.msg_fail_unlock));
- mButton2.setEnabled(true);
- changeState(STATE_UNBLOCK);
- }
-
- private void updateToSuccess() {
- mFlipper.setDisplayedChild(2);
- setSuccesfullyCalibrated(this, true);
- mText2.setText(R.string.msg_step_success);
- mButton3.setEnabled(true);
- }
-
- private void updateToUnblockRead() {
- mText2.setText(getString(R.string.msg_reading));
- mButton2.setEnabled(false);
- mProgressBar2.setVisibility(View.VISIBLE);
- new Thread(new Runnable() {
- @Override
- public void run() {
- final int value = read(READ_MIN_LIMIT, (mDataNear + OFFSET_NEAR - 5));
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Log.d(TAG, "unblock value = " + String.format("%3d", value) + " (" + String.format("0x%04x", value) + ")");
- if (value >= 0 && value <= (mDataNear + OFFSET_NEAR - 5)) {
- mDataFar = mDataNear - OFFSET_FAR;
- mDataOffset = DEFAULT_OFFSET;
- changeState(STATE_CAL);
- } else {
- mText1.setText(getString(R.string.msg_fail_unlock));
- changeState(STATE_FAIL_STEP_2);
- }
- }
- });
- }
- }).start();
}
@Override
@@ -311,152 +375,6 @@
super.onPause();
}
- private void updateToUnblock() {
- mFlipper.setDisplayedChild(1);
- mProgressBar2.setVisibility(View.INVISIBLE);
- mStep2.setEnabled(true);
- mText2.setEnabled(true);
- mButton2.setEnabled(true);
- }
-
- /**
- * Call to read(1, {@link #READ_MIN_LIMIT}, {@link #READ_MAX_LIMIT})
- *
- * @return The value read or -1 if read failed.
- * @see #read(int, int, int)
- */
- public static int read() {
- return read(1, READ_MIN_LIMIT, READ_MAX_LIMIT);
- }
-
- /**
- * Call to read({@link #READ_N_TIMES}, min_value, max_value)
- *
- * @param min_value The lower threshold (inclusive) of accepted range.
- * @param max_value The upper threshold (inclusive) of accepted range.
- * @return The mean of all the value read (up to {@link #READ_N_TIMES}) or -1 if no read succeeded.
- * @see #read(int, int, int)
- */
- public static int read(int min_value, int max_value) {
- return read(READ_N_TIMES, min_value, max_value);
- }
-
- /**
- * Read the proximity sensor value read_times times and return the mean value.
- *
- * Wait {@link #READ_DELAY} between each read, even if there is only one read planned.
- *
- * @param min_value The lower threshold (inclusive) of accepted range.
- * @param max_value The upper threshold (inclusive) of accepted range.
- * @return The mean of all the value read (up to {@link #READ_N_TIMES}) or -1 if no read succeeded.
- */
- public static int read(int read_times, int min_value, int max_value) {
- String line;
- int result;
- int summed_result = 0;
- int nb_result_read = 0;
- int final_result = -1;
-
- for (int i = 0; i < read_times; i++) {
- line = exec(CMD);
-
- if (line != null && line.startsWith(RESULT_PREFIX)) {
- try {
- result = Integer.parseInt( line.replace(RESULT_PREFIX, "").trim() );
-
- if (min_value <= result && result <= max_value) {
- summed_result += result;
- nb_result_read++;
- } else {
- Log.d(TAG, "Ignored value out of accepted range (" + result + " not in [" + min_value + "," + max_value + "])");
- }
- } catch (Exception e) {
- Log.wtf(TAG, e);
- }
- }
-
- // wait a bit between two sensor read
- try {
- Thread.sleep(READ_DELAY);
- } catch (Exception e) {
- Log.wtf(TAG, e);
- }
- }
-
- if (nb_result_read == 0) {
- // something went wrong with CMD, are we allowed to execute it?
- Log.e(TAG, "Could not read sensor value " + read_times + " " + ((read_times==1) ? "time" : "times"));
-
- // TODO display an error message
- } else {
- if (nb_result_read < read_times) {
- Log.w(TAG, "Read " + nb_result_read + "/" + read_times + " values");
- }
-
- final_result = Math.round(summed_result / nb_result_read);
- }
-
- return final_result;
- }
-
- private void getPersistedValues() {
- byte[] buffer = new byte[4];
- buffer[2] = 0x00;
- buffer[3] = 0x00;
- try {
- RandomAccessFile file = new RandomAccessFile(CALIBRATION_FILE, "r");
-
- file.seek(SEEK_NEAR);
- file.read(buffer, 0, 2);
- mPersistedDataNear = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
- Log.d(getString(R.string.logtag), "persisted near data = " + String.format("%3d", mPersistedDataNear) + " (" + String.format("0x%02x%02x", buffer[1], buffer[0]) + ")");
-
- file.seek(SEEK_FAR);
- file.read(buffer, 0, 2);
- mPersistedDataFar = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
- Log.d(getString(R.string.logtag), "persisted far data = " + String.format("%3d", mPersistedDataFar) + " (" + String.format("0x%02x%02x", buffer[1], buffer[0]) + ")");
-
- file.seek(SEEK_OFFSET);
- file.read(buffer, 0, 1);
- buffer[1] = 0x00;
- mPersistedDataOffset = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
- Log.d(getString(R.string.logtag), "persisted offset data = " + String.format("%3d", mPersistedDataOffset) + " (" + String.format("0x%02x", buffer[0]) + ")");
-
- file.close();
- } catch (Exception e) {
- Log.wtf(TAG, e);
- }
- }
-
-
- private boolean write() {
- byte[] far = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(mDataFar).array();
- byte[] near = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(mDataNear).array();
- byte[] offset = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(mDataOffset).array();
-
- Log.d(getString(R.string.logtag), "near data = " + String.format("%3d", mDataNear) + " (" + String.format("0x%02x%02x", near[1], near[0]) + ")");
- Log.d(getString(R.string.logtag), "far data = " + String.format("%3d", mDataFar) + " (" + String.format("0x%02x%02x", far[1], far[0]) + ")");
- Log.d(getString(R.string.logtag), "offset data = " + String.format("%3d", mDataOffset) + " (" + String.format("0x%02x", offset[0]) + ")");
-
- try {
- RandomAccessFile file = new RandomAccessFile(CALIBRATION_FILE, "rw");
- file.seek(SEEK_NEAR);
- file.writeByte(near[0]);
- file.writeByte(near[1]);
- file.seek(SEEK_FAR);
- file.writeByte(far[0]);
- file.writeByte(far[1]);
- file.seek(SEEK_OFFSET);
- file.writeByte(offset[0]);
- file.close();
- storeCalibrationData();
- return true;
- } catch (Exception e) {
- Log.wtf(TAG, e);
- }
- return false;
- }
-
private void storeCalibrationData() {
CalibrationDbHelper mDbHelper = new CalibrationDbHelper(this);
@@ -465,18 +383,18 @@
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
- values.put(CalibrationData.COLUMN_NAME_PREVIOUS_NEAR, mPersistedDataNear);
- values.put(CalibrationData.COLUMN_NAME_PREVIOUS_FAR, mPersistedDataFar);
- values.put(CalibrationData.COLUMN_NAME_PREVIOUS_OFFSET, mPersistedDataOffset);
- values.put(CalibrationData.COLUMN_NAME_NEAR, mDataNear);
- values.put(CalibrationData.COLUMN_NAME_FAR, mDataFar);
- values.put(CalibrationData.COLUMN_NAME_OFFSET, mDataOffset);
+ values.put(CalibrationData.COLUMN_NAME_PREVIOUS_NEAR, mPersistedConfiguration.nearThreshold);
+ values.put(CalibrationData.COLUMN_NAME_PREVIOUS_FAR, mPersistedConfiguration.farThreshold);
+ values.put(CalibrationData.COLUMN_NAME_PREVIOUS_OFFSET, mPersistedConfiguration.offsetCompensation);
+ values.put(CalibrationData.COLUMN_NAME_NEAR, mCalibratedConfiguration.nearThreshold);
+ values.put(CalibrationData.COLUMN_NAME_FAR, mCalibratedConfiguration.farThreshold);
+ values.put(CalibrationData.COLUMN_NAME_OFFSET, mCalibratedConfiguration.offsetCompensation);
PackageInfo pInfo = null;
try {
pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
+ Log.wtf(TAG, e);
}
int verCode = pInfo.versionCode;
values.put(CalibrationData.COLUMN_NAME_APP_VERSION, verCode);
@@ -490,43 +408,30 @@
}
- private static String exec(String cmd) {
- try {
- Process proc = Runtime.getRuntime().exec(new String[]{cmd});
- BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
- return reader.readLine();
- } catch (IOException e) {
- Log.wtf(TAG, "Could not execute command `" + cmd + "`", e);
- return null;
- }
+ private void startFairphoneUpdaterActivity() {
+ final Intent intent = new Intent();
+ intent.setComponent(new ComponentName(getString(R.string.package_fairphone_updater), getString(R.string.activity_fairphone_updater_check_for_updates)));
+ intent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
}
- protected static void setSuccesfullyCalibrated(Context ctx, boolean isSuccessfullyCalibrated) {
- SharedPreferences sharedPref = ctx.getSharedPreferences(
- ctx.getString(R.string.preference_file_key), MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putBoolean(ctx.getString(R.string.preference_successfully_calibrated),isSuccessfullyCalibrated);
- editor.apply();
+ private void showIncompatibleDeviceDialog() {
+ final DialogFragment dialog = new IncompatibleDeviceDialog();
+ dialog.show(getFragmentManager(), getString(R.string.fragment_tag_incompatible_device_dialog));
}
- protected static boolean hasToBeCalibrated(Context ctx) {
- SharedPreferences sharedPref = ctx.getSharedPreferences(
- ctx.getString(R.string.preference_file_key), MODE_PRIVATE);
- boolean wasCalibrated = sharedPref.getBoolean(ctx.getString(R.string.preference_successfully_calibrated),false);
- boolean wasCalibratedEarlier = false;
- try {
- RandomAccessFile file = new RandomAccessFile(CALIBRATION_FILE, "rw");
- file.seek(SEEK_NEAR);
- file.seek(SEEK_OFFSET);
- byte offset0 = file.readByte();
- byte offset1 = file.readByte();
- file.close();
- /* offset is only 0 on devices that have not been calibrated. */
- wasCalibratedEarlier = (offset0 != 0 || offset1 != 0);
- } catch (Exception e) {
- Log.wtf(TAG, e);
- }
- return !wasCalibrated;
+ @Override
+ public void onIncompatibleDeviceDialogPositiveAction(DialogFragment dialog) {
+ startFairphoneUpdaterActivity();
}
+ @Override
+ public void onIncompatibleDeviceDialogNegativeAction(DialogFragment dialog) {
+ // fall-through
+ }
+
+ @Override
+ public void onDismissIncompatibleDeviceDialog(DialogFragment dialog) {
+ finish();
+ }
}
diff --git a/app/src/main/java/com/fairphone/psensor/DiagnosticsActivity.java b/app/src/main/java/com/fairphone/psensor/DiagnosticsActivity.java
index 821b828..d646bea 100644
--- a/app/src/main/java/com/fairphone/psensor/DiagnosticsActivity.java
+++ b/app/src/main/java/com/fairphone/psensor/DiagnosticsActivity.java
@@ -11,6 +11,8 @@
import android.util.Log;
import android.widget.TextView;
+import com.fairphone.psensor.helpers.ProximitySensorHelper;
+
public class DiagnosticsActivity extends Activity {
private int mSensorChangeCount = 0;
@@ -26,10 +28,16 @@
private Handler mHandler;
+ private ProximitySensorConfiguration mPersistedConfiguration;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ mPersistedConfiguration = ProximitySensorConfiguration.readFromMemory();
mHandler = new Handler();
+
+
setContentView(R.layout.activity_diagnostics);
// mActionBar = getActionBar();
@@ -42,8 +50,8 @@
mBlockValueTextView = (TextView)findViewById(R.id.blockValue);
mUnblockValueTextView = (TextView)findViewById(R.id.unblockValue);
- mBlockValueTextView.setText(String.valueOf(CalibrationActivity.BLOCK_LIMIT - CalibrationActivity.OFFSET_NEAR));
- mUnblockValueTextView.setText(String.valueOf(CalibrationActivity.UNBLOCK_LIMIT - CalibrationActivity.OFFSET_FAR));
+ mBlockValueTextView.setText(mPersistedConfiguration.nearThreshold);
+ mUnblockValueTextView.setText(mPersistedConfiguration.farThreshold);
getProximitySensor();
setupSensorStateListener();
@@ -54,7 +62,7 @@
@Override
public void run() {
try {
- sensorValue = CalibrationActivity.read();
+ sensorValue = ProximitySensorHelper.read();
Log.i(DiagnosticsActivity.class.getName(), String.valueOf(sensorValue));
runOnUiThread(new Runnable() {
@Override
diff --git a/app/src/main/java/com/fairphone/psensor/ProximitySensorConfiguration.java b/app/src/main/java/com/fairphone/psensor/ProximitySensorConfiguration.java
new file mode 100644
index 0000000..4bea788
--- /dev/null
+++ b/app/src/main/java/com/fairphone/psensor/ProximitySensorConfiguration.java
@@ -0,0 +1,222 @@
+package com.fairphone.psensor;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Locale;
+
+/**
+ * Configuration fields for the proximity sensor. <br>
+ * <br>
+ * Using the vendor wording, the "near threshold" is the "Proximity Interrupt High threshold", the "far threshold"
+ * is the "Proximity Interrupt LOW threshold", and the "offset compensation" is the "Proximity Offset Compensation".
+ */
+public class ProximitySensorConfiguration {
+ private static final String TAG = ProximitySensorConfiguration.class.getSimpleName();
+
+ /**
+ * Minimal offset compensation value allowed to be persisted. <br>
+ * The minimal value accepted in the registry is <code>0x0000</code>, whereas this is the minimal value considered
+ * sane from a tuning perspective.
+ */
+ public static final int MIN_OFFSET_COMPENSATION = 0x0000;
+ /**
+ * Maximal offset compensation value allowed to be persisted. <br>
+ * The maximal value accepted in the registry is <code>0xFFFF</code>, whereas this is the maximal value considered
+ * sane from a tuning perspective.
+ */
+ public static final int MAX_OFFSET_COMPENSATION = 0x00FF;
+ /**
+ * Minimal near threshold value allowed to be persisted. <br>
+ * The minimal value accepted in the registry is <code>0x0000</code>, whereas this is the minimal value considered
+ * sane from a tuning perspective.
+ */
+ public static final int MIN_NEAR_THRESHOLD = 0x0000;
+ /**
+ * Maximal near threshold value allowed to be persisted. <br>
+ * The maximal value accepted in the registry is <code>0xFFFF</code>, whereas this is the maximal value considered
+ * sane from a tuning perspective.
+ */
+ public static final int MAX_NEAR_THRESHOLD = 0x00FF;
+ /**
+ * Minimal far threshold value allowed to be persisted. <br>
+ * The minimal value accepted in the registry is <code>0x0000</code>, whereas this is the minimal value considered
+ * sane from a tuning perspective.
+ */
+ public static final int MIN_FAR_THRESHOLD = 0x0000;
+ /**
+ * Maximal far threshold value allowed to be persisted. <br>
+ * The maximal value accepted in the registry is <code>0xFFFF</code>, whereas this is the maximal value considered
+ * sane from a tuning perspective.
+ */
+ public static final int MAX_FAR_THRESHOLD = 0x00FF;
+
+ /**
+ * Default value for the offset compensation.
+ */
+ private static final int DEFAULT_OFFSET_COMPENSATION = 0x0001;
+ /**
+ * Default value for the near threshold.
+ */
+ private static final int DEFAULT_NEAR_THRESHOLD = 0x00FF;
+ /**
+ * Default value for the far threshold.
+ */
+ private static final int DEFAULT_FAR_THRESHOLD = 0x0000;
+
+ /**
+ * Path to the persisted calibration file.
+ */
+ private static final String CALIBRATION_FILE = "/persist/sns.reg";
+ /**
+ * Offset in the calibration file to reach the offset compensation value.
+ */
+ private static final int OFFSET_COMPENSATION_OFFSET = 0x00000120 + 8;
+ /**
+ * Offset in the calibration file to reach the near threshold value.
+ */
+ private static final int NEAR_THRESHOLD_OFFSET = 0x00000100 + 4;
+ /**
+ * Offset in the calibration file to reach the far threshold value.
+ */
+ private static final int FAR_THRESHOLD_OFFSET = 0x00000100 + 6;
+
+ /**
+ * The proximity sensor offset compensation.
+ */
+ public int offsetCompensation;
+ /**
+ * The proximity sensor interrupt high threshold, to change state from free to blocked.
+ */
+ public int nearThreshold;
+ /**
+ * The proximity sensor interrupt low threshold, to change state from blocked to free.
+ */
+ public int farThreshold;
+
+ /**
+ * Default constructor based on the default values.
+ *
+ * @see #DEFAULT_OFFSET_COMPENSATION
+ * @see #DEFAULT_NEAR_THRESHOLD
+ * @see #DEFAULT_FAR_THRESHOLD
+ */
+ public ProximitySensorConfiguration() {
+ offsetCompensation = DEFAULT_OFFSET_COMPENSATION;
+ nearThreshold = DEFAULT_NEAR_THRESHOLD;
+ farThreshold = DEFAULT_FAR_THRESHOLD;
+ }
+
+ public String toString() {
+ return String.format(Locale.ENGLISH, "{offset compensation=%d, near threshold=%d, far threshold=%d}", offsetCompensation, nearThreshold, farThreshold);
+ }
+
+ /**
+ * Determine whether the memory can be read from and persisted by trying to open a handle to it.
+ *
+ * @return <code>true</code> if the memory is both readable and writable, <code>false</code> if not.
+ */
+ public static boolean canReadFromAndPersistToMemory() {
+ final File calibrationFile = new File(CALIBRATION_FILE);
+
+ return calibrationFile.canRead() && calibrationFile.canWrite();
+ }
+
+ /**
+ * Read the configuration persisted into memory.
+ *
+ * @return The persisted configuration or <code>null</code> if not accessible.
+ */
+ public static ProximitySensorConfiguration readFromMemory() {
+ ProximitySensorConfiguration configuration = new ProximitySensorConfiguration();
+
+ try {
+ byte[] buffer = new byte[4];
+ RandomAccessFile file = new RandomAccessFile(CALIBRATION_FILE, "r");
+
+ file.seek(OFFSET_COMPENSATION_OFFSET);
+ file.read(buffer, 0, 2);
+ configuration.offsetCompensation = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
+
+ file.seek(NEAR_THRESHOLD_OFFSET);
+ file.read(buffer, 0, 2);
+ configuration.nearThreshold = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
+
+ file.seek(FAR_THRESHOLD_OFFSET);
+ file.read(buffer, 0, 2);
+ configuration.farThreshold = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
+
+ file.close();
+
+ Log.d(TAG, "Configuration " + configuration.toString() + " read from `" + CALIBRATION_FILE + "`");
+ } catch (Exception e) {
+ Log.wtf(TAG, e);
+
+ configuration = null;
+ }
+
+ return configuration;
+ }
+
+ /**
+ * Persist the configuration into memory. <br>
+ * <br>
+ * This method <strong>does not</strong> update the current configuration of the proximity sensor. It does set the
+ * values that live in the <code>/persist/</code> directory only.
+ *
+ * @throws IllegalArgumentException if one of the configuration element does not respect the acceptable range
+ * (see {@link #MIN_OFFSET_COMPENSATION}, {@link #MAX_OFFSET_COMPENSATION}, {@link #MIN_NEAR_THRESHOLD},
+ * {@link #MAX_NEAR_THRESHOLD}, {@link #MIN_FAR_THRESHOLD}, and {@link #MAX_FAR_THRESHOLD}).
+ * @return <code>true</code> if the configuration could be persisted, <code>false</code> if it failed.
+ */
+ public boolean persistToMemory() throws IllegalArgumentException {
+ boolean success = false;
+ byte[] buffer;
+ RandomAccessFile file = null;
+
+ if (offsetCompensation < MIN_OFFSET_COMPENSATION || MAX_OFFSET_COMPENSATION < offsetCompensation) {
+ throw new IllegalArgumentException(String.format(Locale.ENGLISH, "Offset compensation (%d) not in the acceptable range [%d;%d]", offsetCompensation, MIN_OFFSET_COMPENSATION, MAX_OFFSET_COMPENSATION));
+ } else if (nearThreshold < MIN_NEAR_THRESHOLD || MAX_NEAR_THRESHOLD < nearThreshold) {
+ throw new IllegalArgumentException(String.format(Locale.ENGLISH, "Near threshold (%d) not in the acceptable range [%d;%d]", nearThreshold, MIN_NEAR_THRESHOLD, MAX_NEAR_THRESHOLD));
+ }if (farThreshold < MIN_FAR_THRESHOLD || MAX_FAR_THRESHOLD < farThreshold) {
+ throw new IllegalArgumentException(String.format(Locale.ENGLISH, "Far threshold (%d) not in the acceptable range [%d;%d]", farThreshold, MIN_FAR_THRESHOLD, MAX_FAR_THRESHOLD));
+ }
+
+ try {
+ file = new RandomAccessFile(CALIBRATION_FILE, "rw");
+
+ file.seek(OFFSET_COMPENSATION_OFFSET);
+ buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(offsetCompensation).array();
+ file.write(buffer, 0, 2);
+
+ file.seek(NEAR_THRESHOLD_OFFSET);
+ buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(nearThreshold).array();
+ file.write(buffer, 0, 2);
+
+ file.seek(FAR_THRESHOLD_OFFSET);
+ buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(farThreshold).array();
+ file.write(buffer, 0, 2);
+
+ file.close();
+ success = true;
+
+ Log.d(TAG, "Configuration " + this.toString() + " persisted to `" + CALIBRATION_FILE + "`");
+ } catch (Exception e) {
+ Log.wtf(TAG, e);
+ } finally {
+ if (file != null) {
+ try {
+ file.close();
+ } catch (IOException e) {
+ // fall-through
+ }
+ }
+ }
+
+ return success;
+ }
+}
diff --git a/app/src/main/java/com/fairphone/psensor/UpdateFinalizerActivity.java b/app/src/main/java/com/fairphone/psensor/UpdateFinalizerActivity.java
index c3051d3..5bf3bc0 100644
--- a/app/src/main/java/com/fairphone/psensor/UpdateFinalizerActivity.java
+++ b/app/src/main/java/com/fairphone/psensor/UpdateFinalizerActivity.java
@@ -22,7 +22,6 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.app.AlertDialog;
import android.app.Activity;
@@ -35,6 +34,8 @@
import android.widget.CompoundButton;
import android.widget.TextView;
+import com.fairphone.psensor.helpers.CalibrationStatusHelper;
+
public class UpdateFinalizerActivity extends Activity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
@@ -65,14 +66,14 @@
}
- mTextViewMain = (TextView) findViewById(R.id.maintext);
+ mTextViewMain = (TextView) findViewById(R.id.instructions);
mTextViewMain.setText(Html.fromHtml(getString(R.string.Text)));
setAlreadyShown();
UpdateFinalizerService.startActionClearNotification(this);
- if (isWizard() && !CalibrationActivity.hasToBeCalibrated(this)) {
+ if (isWizard() && !CalibrationStatusHelper.hasToBeCalibrated(this)) {
disable(this);
finish();
}
diff --git a/app/src/main/java/com/fairphone/psensor/UpdateFinalizerService.java b/app/src/main/java/com/fairphone/psensor/UpdateFinalizerService.java
index d660376..5fada84 100644
--- a/app/src/main/java/com/fairphone/psensor/UpdateFinalizerService.java
+++ b/app/src/main/java/com/fairphone/psensor/UpdateFinalizerService.java
@@ -11,6 +11,8 @@
import android.support.v4.app.NotificationCompat;
import android.util.Log;
+import com.fairphone.psensor.helpers.CalibrationStatusHelper;
+
public class UpdateFinalizerService extends IntentService {
private static final String ACTION_BOOTUP_COMPLETE = "com.fairphone.updatefinalizer.action.BOOT_COMPLETED";
@@ -81,7 +83,7 @@
private void handleCheckCalibrationPending() {
final Context ctx = this;
- if (!UpdateFinalizerActivityFromNotification.isNotShowAnymore(this) && CalibrationActivity.hasToBeCalibrated(this)) {
+ if (!UpdateFinalizerActivityFromNotification.isNotShowAnymore(this) && CalibrationStatusHelper.hasToBeCalibrated(this)) {
showNotification();
setAlarm();
}
@@ -107,7 +109,7 @@
.bigText(getString(R.string.NotificationText)));
notBuilder.setSmallIcon(R.drawable.ic_stat_action_info);
notBuilder.setContentIntent(pendingIntent);
- notBuilder.setColor(getResources().getColor(R.color.colorPrimary));
+ notBuilder.setColor(getResources().getColor(R.color.theme_primary));
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(mNotificationIDPleaseCalibrate, notBuilder.build());
}
diff --git a/app/src/main/java/com/fairphone/psensor/fragments/IncompatibleDeviceDialog.java b/app/src/main/java/com/fairphone/psensor/fragments/IncompatibleDeviceDialog.java
new file mode 100644
index 0000000..0e92365
--- /dev/null
+++ b/app/src/main/java/com/fairphone/psensor/fragments/IncompatibleDeviceDialog.java
@@ -0,0 +1,73 @@
+package com.fairphone.psensor.fragments;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import com.fairphone.psensor.R;
+
+public class IncompatibleDeviceDialog extends DialogFragment {
+
+ /* The activity that creates an instance of this dialog fragment must
+ * implement this interface in order to receive event callbacks.
+ * Each method passes the DialogFragment in case the host needs to query it. */
+ public interface IncompatibleDeviceDialogListener {
+ void onIncompatibleDeviceDialogPositiveAction(DialogFragment dialog);
+
+ void onIncompatibleDeviceDialogNegativeAction(DialogFragment dialog);
+
+ void onDismissIncompatibleDeviceDialog(DialogFragment dialog);
+ }
+
+ // Use this instance of the interface to deliver action events
+ IncompatibleDeviceDialogListener mListener;
+
+ public IncompatibleDeviceDialog() {
+ // default constructor for easy instantiation
+ }
+
+ // Override the Fragment.onAttach() method to instantiate the EnterTheBetaDialogListener
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ // Verify that the host activity implements the callback interface
+ try {
+ // Instantiate the NoticeDialogListener so we can send events to the host
+ mListener = (IncompatibleDeviceDialogListener) activity;
+ } catch (ClassCastException e) {
+ // The activity doesn't implement the interface, throw exception
+ throw new ClassCastException(activity.toString() + " must implement IncompatibleDeviceDialogListener");
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+ builder.setTitle(R.string.incompatible_device);
+ builder.setMessage(R.string.device_cannot_run_calibration_tool);
+
+ builder.setPositiveButton(R.string.go_to_updater, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ mListener.onIncompatibleDeviceDialogPositiveAction(IncompatibleDeviceDialog.this);
+ }
+ });
+
+ builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ mListener.onIncompatibleDeviceDialogNegativeAction(IncompatibleDeviceDialog.this);
+ }
+ });
+ builder.setCancelable(false);
+
+ return builder.create();
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mListener.onDismissIncompatibleDeviceDialog(this);
+ }
+}
diff --git a/app/src/main/java/com/fairphone/psensor/helpers/CalibrationStatusHelper.java b/app/src/main/java/com/fairphone/psensor/helpers/CalibrationStatusHelper.java
new file mode 100644
index 0000000..22797d7
--- /dev/null
+++ b/app/src/main/java/com/fairphone/psensor/helpers/CalibrationStatusHelper.java
@@ -0,0 +1,94 @@
+package com.fairphone.psensor.helpers;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.fairphone.psensor.ProximitySensorConfiguration;
+import com.fairphone.psensor.R;
+
+/**
+ * Helper methods to access the shared preferences of the app.
+ */
+public class CalibrationStatusHelper {
+
+ /**
+ * Empty constructor to avoid instantiation.
+ */
+ private CalibrationStatusHelper() {
+ }
+
+ /**
+ * Determine if the current device needs to be calibrated.<br>
+ * <br>
+ * The conditions are as follows:
+ * <ol>
+ * <li>The memory needs to be accessible (R/W).</li>
+ * <li>Either: there must not be an evidence that the device has been calibrated in the shared preferences.</li>
+ * <li>Or either: the persisted offset compensation must be equal to 0.</li>
+ * </ol>
+ *
+ * @param context The context.
+ * @param calibrateNullCompensation Flag to decide if the logic is based on the current compensation offset or on
+ * the shared preferences.
+ * @return <em>true</em> if a calibration should take place, <em>false</em> if the device has been calibrated at
+ * one point or if the memory is not accessible.
+ */
+ public static boolean hasToBeCalibrated(Context context, boolean calibrateNullCompensation) {
+ boolean hasToBeCalibrated;
+
+ if (ProximitySensorConfiguration.canReadFromAndPersistToMemory()) {
+ if (calibrateNullCompensation) {
+ final ProximitySensorConfiguration persistedConfiguration = ProximitySensorConfiguration.readFromMemory();
+ hasToBeCalibrated = (persistedConfiguration != null) && (persistedConfiguration.offsetCompensation == 0);
+ } else {
+ final SharedPreferences sharedPref = context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+ hasToBeCalibrated = !sharedPref.getBoolean(context.getString(R.string.preference_successfully_calibrated), false);
+ }
+ } else {
+ /* Memory is not accessible, so no calibration is required. */
+ hasToBeCalibrated = false;
+ }
+
+ return hasToBeCalibrated;
+ }
+
+ /**
+ * Call to <code>hasToBeCalibrated(context, false)</code>.
+ *
+ * @param context The context.
+ * @return <em>true</em> if a calibration should take place, <em>false</em> if the device has been calibrated at
+ * one point.
+ * @see CalibrationStatusHelper#hasToBeCalibrated(Context, boolean)
+ */
+ public static boolean hasToBeCalibrated(Context context) {
+ return hasToBeCalibrated(context, false);
+ }
+
+ public static boolean isCalibrationPending(Context context) {
+ final SharedPreferences sharedPreferences = context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+ return sharedPreferences.getBoolean(context.getString(R.string.preference_pending_calibration), false);
+ }
+
+ public static void setCalibrationCompleted(Context context) {
+ final SharedPreferences sharedPreferences = context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+ final SharedPreferences.Editor editor = sharedPreferences.edit();
+
+ editor.putBoolean(context.getString(R.string.preference_pending_calibration), false);
+
+ editor.apply();
+ }
+
+ public static void setCalibrationSuccessful(Context context) {
+ final SharedPreferences sharedPreferences = context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+ final SharedPreferences.Editor editor = sharedPreferences.edit();
+
+ editor.putBoolean(context.getString(R.string.preference_successfully_calibrated), true);
+ editor.putBoolean(context.getString(R.string.preference_pending_calibration), true);
+
+ editor.apply();
+ }
+}
diff --git a/app/src/main/java/com/fairphone/psensor/helpers/ProximitySensorHelper.java b/app/src/main/java/com/fairphone/psensor/helpers/ProximitySensorHelper.java
new file mode 100644
index 0000000..aa560a9
--- /dev/null
+++ b/app/src/main/java/com/fairphone/psensor/helpers/ProximitySensorHelper.java
@@ -0,0 +1,161 @@
+package com.fairphone.psensor.helpers;
+
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * Helper methods to access the proximity sensor.
+ */
+public class ProximitySensorHelper {
+ private static final String TAG = ProximitySensorHelper.class.getSimpleName();
+
+ /**
+ * Minimal value to accept as valid from the sensor reading (in sensor units).
+ */
+ public static final int READ_MIN_LIMIT = 0;
+ /**
+ * Maximal value to accept as valid from the sensor reading (in sensor units).
+ */
+ public static final int READ_MAX_LIMIT = 255;
+
+ /**
+ * Command to read the sensor value.
+ */
+ private static final String READ_COMMAND = "/system/bin/senread";
+ /**
+ * Result prefix returned by the reading command.
+ */
+ private static final String READ_COMMAND_RESULT_PREFIX = "[RESULT]";
+
+ /**
+ * Amount of times to perform a sensor reading.
+ */
+ private static final int READ_N_TIMES = 3;
+ /**
+ * Time to wait between two sensor readings (in milliseconds).
+ */
+ private static final int READ_DELAY_MS = 500;
+
+ /**
+ * Empty constructor to avoid instantiation.
+ */
+ private ProximitySensorHelper() {
+ }
+
+ /**
+ * Determine whether the proximity sensor value is readable or not based on the reading tool availability. <br>
+ * <br>
+ * The reading tool is tested to exist and be executable.
+ *
+ * @return <code>true</code> if the proximity sensor value is readable, <code>false</code> if not.
+ */
+ public static boolean canReadProximitySensorValue() {
+ final File tool = new File(READ_COMMAND);
+
+ return tool.exists() && tool.canExecute();
+ }
+
+ /**
+ * Read the proximity sensor value read_times times and return the mean value. <br>
+ * <br>
+ * Wait {@link #READ_DELAY_MS} between each read, even if there is only one read planned.
+ *
+ * @param min_value The lower threshold (inclusive) of accepted range.
+ * @param max_value The upper threshold (inclusive) of accepted range.
+ * @return The mean of all the value read (up to {@link #READ_N_TIMES}) or -1 if no read succeeded.
+ */
+ public static int read(int read_times, int min_value, int max_value) {
+ int result;
+ int summed_result = 0;
+ int nb_result_read = 0;
+ int final_result = -1;
+
+ for (int i = 0; i < read_times; i++) {
+ result = readProximitySensorValue();
+
+ if (min_value <= result && result <= max_value) {
+ summed_result += result;
+ nb_result_read++;
+ } else {
+ Log.d(TAG, "Ignored value out of accepted range (" + result + " not in [" + min_value + "," + max_value + "])");
+ }
+
+ // wait a bit between two sensor reading
+ try {
+ Thread.sleep(READ_DELAY_MS);
+ } catch (Exception e) {
+ Log.wtf(TAG, e);
+ }
+ }
+
+ if (nb_result_read == 0) {
+ // something went wrong with READ_COMMAND, are we allowed to execute it?
+ Log.e(TAG, "Could not read sensor value " + read_times + " " + ((read_times == 1) ? "time" : "times"));
+ } else {
+ if (nb_result_read < read_times) {
+ Log.w(TAG, "Read " + nb_result_read + "/" + read_times + " values");
+ }
+
+ final_result = Math.round(summed_result / nb_result_read);
+ }
+
+ return final_result;
+ }
+
+ /**
+ * Call to read(1, {@link #READ_MIN_LIMIT}, {@link #READ_MAX_LIMIT})
+ *
+ * @return The value read or -1 if read failed.
+ * @see ProximitySensorHelper#read(int, int, int)
+ */
+ public static int read() {
+ return read(1, READ_MIN_LIMIT, READ_MAX_LIMIT);
+ }
+
+ /**
+ * Call to read({@link #READ_N_TIMES}, min_value, max_value)
+ *
+ * @param min_value The lower threshold (inclusive) of accepted range.
+ * @param max_value The upper threshold (inclusive) of accepted range.
+ * @return The mean of all the value read (up to {@link #READ_N_TIMES}) or -1 if no read succeeded.
+ * @see ProximitySensorHelper#read(int, int, int)
+ */
+ public static int read(int min_value, int max_value) {
+ return read(READ_N_TIMES, min_value, max_value);
+ }
+
+ /**
+ * Read the proximity sensor value using an external command ({@link #READ_COMMAND}).
+ *
+ * @return the proximity sensor value (>= {@link #READ_MIN_LIMIT and <= {@link #READ_MAX_LIMIT}}) or
+ * <code>-1</code> if there was an error (parsing the value or using the external command).
+ */
+ private static int readProximitySensorValue() {
+ int value = -1;
+ Process process = null;
+
+ try {
+ process = Runtime.getRuntime().exec(new String[]{READ_COMMAND});
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ final String line = reader.readLine();
+
+ if (line != null && line.startsWith(READ_COMMAND_RESULT_PREFIX)) {
+ value = Integer.parseInt(line.replace(READ_COMMAND_RESULT_PREFIX, "").trim());
+ }
+ } catch (IOException e) {
+ Log.wtf(TAG, "Could not execute command `" + READ_COMMAND + "`", e);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, e);
+ } finally {
+ if (process != null) {
+ process.destroy();
+ }
+ }
+
+ return value;
+ }
+}
diff --git a/app/src/main/res/drawable/button_blue_background.xml b/app/src/main/res/drawable/button_blue_background.xml
new file mode 100644
index 0000000..5adfbd8
--- /dev/null
+++ b/app/src/main/res/drawable/button_blue_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@color/blue_light" android:state_enabled="false"/>
+ <item android:drawable="@color/blue_dark" android:state_pressed="true"/>
+ <item android:drawable="@color/blue"/>
+
+</selector>
diff --git a/app/src/main/res/drawable/button_grey_background.xml b/app/src/main/res/drawable/button_grey_background.xml
new file mode 100644
index 0000000..57c942f
--- /dev/null
+++ b/app/src/main/res/drawable/button_grey_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@color/grey_transparent" android:state_enabled="false"/>
+ <item android:drawable="@color/grey" android:state_pressed="true"/>
+ <item android:drawable="@color/grey_light"/>
+
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/button_pink_transparent_background.xml b/app/src/main/res/drawable/button_pink_transparent_background.xml
new file mode 100644
index 0000000..0ea5c09
--- /dev/null
+++ b/app/src/main/res/drawable/button_pink_transparent_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@color/transparent" android:state_enabled="false"/>
+ <item android:drawable="@color/pink_dark" android:state_pressed="true"/>
+ <item android:drawable="@color/pink_light"/>
+
+</selector>
diff --git a/app/src/main/res/drawable/fairphone_button.xml b/app/src/main/res/drawable/fairphone_button.xml
deleted file mode 100644
index a403d23..0000000
--- a/app/src/main/res/drawable/fairphone_button.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<selector
- xmlns:android="http://schemas.android.com/apk/res/android">
-
-<item android:state_enabled="true">
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android">
-
- <padding
- android:left="1dp"
- android:right="1dp"
- android:top="1dp"
- android:bottom="1dp"/>
-
- <solid android:color="@color/theme_primary"/>
- </shape>
-</item>
-
- <item android:state_enabled="false">
- <shape
- xmlns:android="http://schemas.android.com/apk/res/android">
-
- <padding
- android:left="1dp"
- android:right="1dp"
- android:top="1dp"
- android:bottom="1dp"/>
-
- <solid android:color="@color/colorFP2Gray"/>
- </shape>
- </item>
-</selector>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_calibration.xml b/app/src/main/res/layout/activity_calibration.xml
index d9fa826..ebb4f89 100644
--- a/app/src/main/res/layout/activity_calibration.xml
+++ b/app/src/main/res/layout/activity_calibration.xml
@@ -1,32 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical"
- android:layout_height="match_parent"
android:layout_width="match_parent"
- android:background="@color/colorFP2Background">
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="100dp"
- android:background="@color/colorFP2HeaderBackground">
-
- <TextView
- android:text="@string/app_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:fontFamily="sans-serif-light"
- android:textColor="@color/colorPrimary"
- android:textSize="30sp"/>
-
- </RelativeLayout>
+ <include layout="@layout/header_app" />
<ViewFlipper
- android:layout_width="match_parent"
- android:layout_height="match_parent"
android:id="@+id/viewFlipper"
- android:background="@color/colorFP2Background" />
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/app/src/main/res/layout/activity_update_finalizer.xml b/app/src/main/res/layout/activity_update_finalizer.xml
index f11a4c8..c1c43b3 100644
--- a/app/src/main/res/layout/activity_update_finalizer.xml
+++ b/app/src/main/res/layout/activity_update_finalizer.xml
@@ -4,102 +4,55 @@
android:id="@+id/activity_update_finalizer"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:orientation="vertical"
tools:context="com.fairphone.psensor.UpdateFinalizerActivity">
- <LinearLayout
+ <include layout="@layout/header_wizard" />
+
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:background="@color/background"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:padding="@dimen/main_padding">
- <RelativeLayout
+ <TextView
+ android:id="@+id/heading"
+ style="@style/TextBold16BlueDark"
android:layout_width="match_parent"
- android:layout_height="100dp"
- android:background="@color/colorFP2HeaderBackground">
+ android:layout_height="wrap_content"
+ android:text="@string/greating"
+ android:textIsSelectable="false" />
- <TextView
- android:id="@+id/textView4"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:fontFamily="sans-serif-light"
- android:textColor="@color/colorPrimary"
- android:textSize="36sp"
- android:text="@string/Heading"
- tools:text="@string/Heading" />
- </RelativeLayout>
-
- <RelativeLayout
+ <TextView
+ android:id="@+id/instructions"
+ style="@style/TextRegular14BlueDark"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/colorFP2Background">
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/heading"
+ android:layout_marginTop="@dimen/main_small_text_below_heading_margin"
+ android:text="@string/Text" />
- <Button
- android:id="@+id/button_next"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="34dp"
- android:layout_marginLeft="20dp"
- android:layout_marginRight="20dp"
- android:background="@color/colorPrimary"
- android:fontFamily="sans-serif-light"
- android:text="@string/next"
- android:textColor="@color/colorFP2ButtonText"
- android:textSize="24sp" />
+ <CheckBox
+ android:id="@+id/checkBoxSuppress"
+ style="@style/TextRegular14BlueDark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/button_next"
+ android:text="@string/dontshowagain"
+ android:layout_marginBottom="@dimen/main_margin_small"
+ android:enabled="false" />
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_above="@+id/button_next"
- android:layout_alignParentEnd="true"
- android:layout_marginBottom="32dp">
+ <Button
+ android:id="@+id/button_next"
+ style="@style/ButtonWhiteBlue"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:text="@string/next" />
- <TextView
- android:id="@+id/textView2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_marginEnd="30dp"
- android:layout_marginStart="30dp"
- android:layout_marginTop="50dp"
- android:text="@string/greating"
- android:textAllCaps="false"
- android:textColor="@color/colorFP2Text"
- android:textIsSelectable="false"
- android:textSize="15sp"
- android:textStyle="bold"
- android:typeface="sans" />
-
- <TextView
- android:id="@+id/maintext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignStart="@+id/textView2"
- android:layout_below="@+id/textView2"
- android:layout_marginEnd="30dp"
- android:layout_marginTop="20dp"
- android:fontFamily="sans-serif-light"
- android:lineSpacingExtra="3sp"
- android:text="@string/Text"
- android:textColor="@color/colorFP2Text"
- android:textSize="15sp" />
-
- <CheckBox
- android:text="@string/dontshowagain"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/checkBoxSuppress"
- android:fontFamily="sans-serif-light"
- android:textColor="@color/colorFP2Text"
- android:layout_alignParentBottom="true"
- android:layout_alignEnd="@+id/maintext" />
- </RelativeLayout>
-
- </RelativeLayout>
-
- </LinearLayout>
+ </RelativeLayout>
</LinearLayout>
diff --git a/app/src/main/res/layout/header_app.xml b/app/src/main/res/layout/header_app.xml
new file mode 100644
index 0000000..ecfc79b
--- /dev/null
+++ b/app/src/main/res/layout/header_app.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/background_header">
+
+ <TextView
+ style="@style/TitleLightPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/header_big_height"
+ android:paddingStart="@dimen/header_padding"
+ android:paddingEnd="@dimen/header_padding"
+ android:ellipsize="end"
+ android:gravity="center_vertical|center_horizontal"
+ android:lines="2"
+ android:text="@string/app_name" />
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/header_wizard.xml b/app/src/main/res/layout/header_wizard.xml
new file mode 100644
index 0000000..7f2853e
--- /dev/null
+++ b/app/src/main/res/layout/header_wizard.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/background_header">
+
+ <TextView
+ style="@style/TitleLightPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/header_big_height"
+ android:ellipsize="end"
+ android:gravity="center_vertical|center_horizontal"
+ android:lines="2"
+ android:text="@string/Heading" />
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/view_calibration_step.xml b/app/src/main/res/layout/view_calibration_step.xml
index 5ad76a3..7657336 100644
--- a/app/src/main/res/layout/view_calibration_step.xml
+++ b/app/src/main/res/layout/view_calibration_step.xml
@@ -1,74 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical" android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/colorFP2Background">
-
- <TextView
- android:id="@+id/maintext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:fontFamily="sans-serif-light"
- android:lineSpacingExtra="3sp"
- android:text="@string/msg_block"
- android:textColor="@color/colorFP2Text"
- android:textSize="15sp"
- android:layout_marginEnd="30dp"
-
- android:layout_below="@+id/textview_heading"
- android:layout_alignStart="@+id/textview_heading"
- android:layout_alignParentEnd="true" />
-
- <TextView
- android:id="@+id/textview_heading"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/step_1"
- android:textAllCaps="false"
- android:textColor="@color/colorFP2Text"
- android:textIsSelectable="false"
- android:textSize="15sp"
- android:textStyle="bold"
- android:typeface="sans"
- android:layout_below="@+id/instructionImage"
- android:layout_marginEnd="30dp"
- android:layout_marginStart="30dp"
- />
-
- <Button
- android:id="@+id/button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="20dp"
- android:layout_marginRight="20dp"
- android:background="@drawable/fairphone_button"
- android:fontFamily="sans-serif-light"
- android:text="@string/next"
- android:textColor="@color/colorFP2ButtonText"
- android:textSize="24sp"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="30dp" />
+ android:layout_width="match_parent" android:layout_height="match_parent"
+ android:background="@color/background"
+ android:paddingLeft="@dimen/main_padding"
+ android:paddingRight="@dimen/main_padding">
<ImageView
- android:id="@+id/instructionImage"
- android:src="@drawable/top_image_psensor"
+ android:id="@+id/instruction_image"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginLeft="15dp"
- android:layout_marginRight="15dp"
android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true" />
+ android:layout_centerHorizontal="true"
+ android:src="@drawable/top_image_psensor" />
+
+ <TextView
+ android:id="@+id/current_step"
+ style="@style/TextBold16BlueDark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/instruction_image"
+ android:text="@string/step_1" />
+
+ <TextView
+ android:id="@+id/instructions"
+ style="@style/TextRegular14BlueDark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/current_step"
+ android:layout_marginTop="@dimen/main_small_text_below_heading_margin"
+ android:text="@string/msg_block" />
+
+ <TextView
+ android:id="@+id/error_notice"
+ style="@style/TextRegular14PinkDark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/instructions"
+ android:layout_marginTop="@dimen/main_small_text_below_heading_margin"
+ android:text="@string/msg_fail_block" />
<ProgressBar
+ android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/progressBar"
- android:layout_marginBottom="57dp"
- android:visibility="invisible"
android:layout_above="@+id/button"
- android:layout_centerHorizontal="true" />
-</RelativeLayout>
\ No newline at end of file
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/main_margin"
+ android:indeterminate="true" />
+
+ <Button
+ android:id="@+id/button"
+ style="@style/ButtonWhiteBlue"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/main_margin"
+ android:text="@string/next" />
+
+</RelativeLayout>
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_settings.png b/app/src/main/res/mipmap-hdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..252e6b4
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_settings.png b/app/src/main/res/mipmap-mdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..d2ecee9
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher_settings.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_settings.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..fa8c813
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_settings.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..3fa69e9
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..72946b7
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 4e89569..4d64b0c 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">Näherungssensorwerkzeug</string>
<string name="Exit">Schließen</string>
@@ -14,27 +14,27 @@
<string name="cancel">Abbrechen</string>
<string name="dontshowagain">Diese Meldung künftig nicht mehr zeigen.</string>
<string name="greating">Näherungssensorkalibrierung</string>
- <string name="msg_block">Decke den Sensorbereich komplett mit deinem Finger ab (der Sensorbereich ist im obigen Bild hervorgehoben) und drücke gleichzeitig auf OK.</string>
- <string name="msg_cal">Kalibrieren...</string>
+ <string name="msg_block">Decke den Sensorbereich komplett mit deinem Finger ab (der Sensorbereich ist im obigen Bild hervorgehoben) und drücke gleichzeitig auf Weiter.</string>
+ <string name="msg_cal">Kalibrieren…</string>
<string name="msg_calibration_success"><![CDATA[Kalibrierung erfolgreich. Drücke auf "OK & Neustart" um die Kalibrierung abzuschließen und dein Fairphone neu zu starten.]]></string>
<string name="reboot"><![CDATA[OK & Neustart]]></string>
<string name="msg_fail">Fehler</string>
<string name="msg_fail_block">Hier ging was schief. Bitte probier es noch einmal. Achte darauf den Sensorbereich komplett abzudecken.</string>
<string name="msg_fail_cal">Kalibrierung fehlgeschlagen. Bitte überprüfe das Gerät und versuch es noch einmal.</string>
<string name="msg_fail_unlock">Hier ging was schief. Bitte probier es noch einmal. Stelle sicher, dass der Sensorbereich frei und der Bildschirm sauber sind.</string>
- <string name="msg_fail_write_sns">Ein unerwartetes Problem mit Rechten ist aufgetreten...</string>
- <string name="msg_reading">Lesen...</string>
+ <string name="msg_fail_write_sns">Ein unerwartetes Problem mit Rechten ist aufgetreten…</string>
+ <string name="msg_reading">Lesen…</string>
<string name="msg_step_success">Fertig</string>
- <string name="msg_unblock">Entferne deinen Finger vom Sensorbereich und drücke danach auf OK.</string>
+ <string name="msg_unblock">Entferne deinen Finger vom Sensorbereich und drücke danach auf Weiter.</string>
<string name="name_exit">Schließen</string>
<string name="name_read">OK</string>
<string name="next">Weiter</string>
<string name="not_triggered">Nicht aktiviert</string>
<string name="sensor_value">Sensorwert:</string>
<string name="state">Status:</string>
- <string name="step_1">Schritt 1</string>
- <string name="step_2">Schritt 2</string>
- <string name="step_3">Schritt 3</string>
+ <string name="step_1">Schritt 1/3</string>
+ <string name="step_2">Schritt 2/3</string>
+ <string name="step_3">Schritt 3/3</string>
<string name="unblock_value">Wert wenn frei:</string>
<string name="NotificationTitle">Näherungssensorkalibrierung</string>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 0134ac7..9cada09 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">Herramienta Sensor de proximidad</string>
<string name="Exit">Salir</string>
@@ -6,25 +6,25 @@
<string name="Text"><![CDATA[ <p>Fairphone OS te da la opción de calibrar el sensor de proximidad - esto mejorará el funcionamiento del sensor mientras haces una llamada (la pantalla se encenderá cuando terminas la llamada).</p> <p>Te recomendamos calibrar el sensor de proximidad ahora para tener el mejor funcionamiento - es fácil y rápido!</p>]]></string>
<string name="activity_calibration">Calibración</string>
<string name="activity_diagnostics">Diagnóstico</string>
- <string name="msg_block">Cubre el area del sensor de proximidad con el dedo (el area a cubrir esta indicada en la imagen superior), luego pulsa OK.</string>
+ <string name="msg_block">Cubre el área del sensor de proximidad con el dedo (el área a cubrir esta indicada en la imagen superior), luego pulsa Próximo.</string>
<string name="msg_cal">Calibrando…</string>
<string name="msg_calibration_success"><![CDATA[Calibración lista! Pulsa OK para finalizar el proceso y reiniciar tu Fairphone.]]></string>
<string name="msg_step_success">Listo</string>
<string name="msg_fail">Fallido</string>
- <string name="msg_fail_block">Ha habido un error; por favor inténtalo de nuevo. Asegúrate de cubrir el area del sensor completamente. </string>
+ <string name="msg_fail_block">Ha habido un error; por favor inténtalo de nuevo. Asegúrate de cubrir el área del sensor completamente. </string>
<string name="msg_fail_cal">Calibración fallida. Comprueba el teléfono e inténtalo de nuevo.</string>
<string name="msg_fail_unlock">Algo ha fallado. Por favor inténtalo de nuevo. Asegúrate de que el sensor de proximidad no está cubierto y la pantalla esta limpia.</string>
- <string name="msg_fail_write_sns">Problema inesperado de permisos...</string>
- <string name="msg_reading">En proceso...</string>
- <string name="msg_unblock">Retira el dedo del sensor y pulsa OK.</string>
+ <string name="msg_fail_write_sns">Problema inesperado de permisos…</string>
+ <string name="msg_reading">En proceso…</string>
+ <string name="msg_unblock">Retira el dedo del sensor y pulsa Próximo.</string>
<string name="name_exit">Salir</string>
<string name="name_read">OK</string>
<string name="next">Próximo</string>
<string name="dontshowagain">No mostrar esta pantalla de nuevo.</string>
<string name="unblock_value">Valor sensor libre:</string>
- <string name="step_1">Paso 1</string>
- <string name="step_2">Paso 2</string>
- <string name="step_3">Paso 3</string>
+ <string name="step_1">Paso 1/3</string>
+ <string name="step_2">Paso 2/3</string>
+ <string name="step_3">Paso 3/3</string>
<string name="state">Estado:</string>
<string name="sensor_value">Valor sensor:</string>
<string name="reboot"><![CDATA[Aceptar y Reiniciar]]></string>
@@ -36,5 +36,5 @@
<string name="ask_really_dont_show_title">¿Estás seguro?</string>
<string name="ask_really_dont_show_text"><![CDATA[Calibrar el sensor de proximidad es fácil y mejorará tu experiencia cuando llames. <it>Puedes calibrar el sensor de proximidad en otro momento en Ajustes → Mantenimiento → Herramienta Sensor de Proximidad</it>.]]></string>
<string name="block_value">Valor de bloqueo:</string>
- <string name="Heading">Una cosa más...</string>
+ <string name="Heading">Una cosa más…</string>
</resources>
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 326d011..7a0a221 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">Capteur de proximité</string>
<string name="Exit">Quitter</string>
@@ -8,33 +8,37 @@
<string name="Text"><![CDATA[ <p>Vous avez désormais la possibilité de calibrer le capteur de proximité depuis Fairphone OS - ceci améliore le comportement du capteur lors d’un appel (l’écran s’éteint/s’allume).</p> <p>Nous recommandons de calibrer le capteur de proximité maintenant pour une meilleure expérience - cela ne vous prendra qu’une minute!</p>]]></string>
<string name="activity_calibration">Calibration</string>
<string name="activity_diagnostics">Diagnostique</string>
- <string name="ask_really_dont_show_title">Êtes-vous sûr?</string>
+ <string name="ask_really_dont_show_title">Êtes-vous sûr ?</string>
<string name="block_value">Valeur à l\'état «bloqué» :</string>
<string name="dontshowagain">Ne plus afficher cet écran.</string>
<string name="greating">Calibration du capteur de proximité</string>
- <string name="msg_block">Recouvrez la zone du capteur entièrement avec votre doigt (la zone à couvrir est illustrée par l\'image ci-dessus), puis utilisez le bouton OK.</string>
+ <string name="msg_block">Recouvrez la zone du capteur entièrement avec votre doigt (la zone à couvrir est illustrée par l\'image ci-dessus), puis utilisez le bouton Suivant.</string>
<string name="msg_cal">Calibration en cours…</string>
<string name="msg_calibration_success"><![CDATA[Calibration terminée ! Utilisez le bouton OK & Redémarrer pour finaliser la procédure et redémarrer votre Fairphone.]]></string>
<string name="msg_fail">Échec</string>
<string name="msg_fail_block">Une erreur est survenue, merci de recommencer. Assurez vous de couvrir complètement la zone du capteur.</string>
<string name="msg_fail_cal">Échec de la calibration. Veuillez vérifier votre téléphone puis recommencer.</string>
<string name="msg_fail_unlock">Une erreur est survenue, merci de recommencer. Assurez vous d\'emlever votre doigt de la zone du capteur et de vérifier que votre écran est propre.</string>
- <string name="msg_fail_write_sns">Erreur exceptionnelle de permission…</string>
- <string name="msg_reading">Lecture en cours…</string>
+ <string name="msg_fail_write_sns">Une erreur est survenue, assurez vous que votre téléphone soit à jour avant de réessayer.</string>
+ <string name="msg_reading">Lecture du capteur de proximité en cours…</string>
<string name="msg_step_success">Succès</string>
- <string name="msg_unblock">Enlevez votre doigt de la zone du capteur puis utilisez le bouton OK.</string>
+ <string name="msg_unblock">Enlevez votre doigt de la zone du capteur puis utilisez le bouton Suivant.</string>
<string name="name_exit">Quitter</string>
<string name="name_read">OK</string>
<string name="next">Suivant</string>
<string name="reboot"><![CDATA[OK & Redémarrer]]></string>
<string name="sensor_value">Valeur du capteur:</string>
<string name="state">État:</string>
- <string name="step_1">Étape 1</string>
- <string name="step_2">Étape 2</string>
- <string name="step_3">Étape 3</string>
+ <string name="step_1">Étape 1/3</string>
+ <string name="step_2">Étape 2/3</string>
+ <string name="step_3">Étape 3/3</string>
<string name="unblock_value">Valeur à l\'état «libre»:</string>
<string name="cancel">Annuler</string>
<string name="NotificationTitle">Calibration du capteur de proximité</string>
<string name="ask_really_dont_show_text"><![CDATA[La calibration du capteur de proximité est simple à réaliser and améliorera votre confort d\'appel. <it>Vous pouvez (re-)calibrer le capteur de proximité à n\'importe quel moment via Paramètres → Maintenance → Capteur de proximité</it>.]]></string>
<string name="not_triggered">Non activé</string>
-</resources>
+<string name="incompatible_device">Équipement incompatible</string>
+ <string name="device_cannot_run_calibration_tool">L\'outil de calibration ne peut pas être exécuté sur votre Fairphone 2. Assurez vous que le système de votre téléphone soit à jour.</string>
+
+ <string name="go_to_updater">Vérifier les mises à jour</string>
+ </resources>
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index da12f74..6e35111 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">Afstandssensor gereedschap</string>
<string name="Exit">Sluit</string>
@@ -12,7 +12,7 @@
<string name="cancel">Annuleer</string>
<string name="dontshowagain">Dit scherm niet meer tonen.</string>
<string name="greating">Afstandssensor kalibratie</string>
- <string name="msg_block">Bedek de sensor volledig met je vinger (het sensor gebied is weergegeven in de afbeelding hierboven) en druk vervolgens op de OK knop.</string>
+ <string name="msg_block">Bedek de sensor volledig met je vinger (het sensor gebied is weergegeven in de afbeelding hierboven) en druk vervolgens op de Volgende knop.</string>
<string name="msg_cal">Kalibreren…</string>
<string name="msg_calibration_success"><![CDATA[Kalibratie succesvol! Druk op de OK & Herstart knop om de kalibratie af te ronden en je Fairphone te herstarten.]]></string>
<string name="Text"><![CDATA[ <p>Fairphone OS geeft je nu de mogelijkheid om de afstandssensor te kalibreren - dit verbetert het gedrag van de sensor tijdens een telefoongesprek (scherm uit/aan).</p> <p>We raden je aan de afstandssensor te kaliberen - dit is eenvoudig en zo gepiept!</p>]]></string>
@@ -23,18 +23,18 @@
<string name="msg_fail_write_sns">Er is onverwacht een permissie probleem opgetreden…</string>
<string name="msg_reading">Controleren…</string>
<string name="msg_step_success">Succesvol</string>
- <string name="msg_unblock">Verwijder je vinger van de sensor en druk op de OK knop.</string>
+ <string name="msg_unblock">Verwijder je vinger van de sensor en druk op de Volgende knop.</string>
<string name="name_exit">Sluit</string>
<string name="name_read">OK</string>
<string name="next">Volgende</string>
<string name="not_triggered">Niet geactiveerd </string>
<string name="reboot"><![CDATA[OK & Herstart]]></string>
<string name="unblock_value">Ontgrendel waarde:</string>
- <string name="step_3">Stap 3</string>
- <string name="step_2">Stap 2</string>
- <string name="step_1">Stap 1</string>
+ <string name="step_3">Stap 3/3</string>
+ <string name="step_2">Stap 2/3</string>
+ <string name="step_1">Stap 1/3</string>
<string name="state">Status</string>
<string name="sensor_value">Sensor waarde:</string>
<string name="ask_really_dont_show_text"><![CDATA[Het kalibreren van de afstandssensor is eenvoudig en verbetert het scherm gedrag tijdens een telefoongesprek (scherm uit/aan). <it>Je kunt de afstandssensor op een later tijdstip kalibreren onder Instellingen → Onderhoud → Afstandssensor gereedschap</it>.]]></string>
<string name="NotificationTitle">Afstandssensor kalibratie</string>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 3f3dff6..06f6015 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,16 +7,30 @@
<color name="theme_primary_dark">#000000</color>
<color name="theme_accent">#f286b6</color>
- <color name="switchbar_background_color">#2aa8e0</color>
- <color name="colorPrimary">#2aa8e0</color>
- <color name="colorPrimaryDark">#000000</color>
- <color name="colorAccent">#f286b6</color>
+ <!-- BACKGROUND -->
+ <color name="background_header">#F7F7F7</color>
+ <color name="background">#F0F0F0</color>
- <color name="colorFP2HeaderBackground">#f7f7f7</color>
- <color name="colorFP2Background">#f0f0f0</color>
- <color name="colorFP2Text">#123c59</color>
- <color name="colorFP2ButtonText">#f7f7f7</color>
- <color name="colorFP2Gray">#a7a7a7</color>
+ <!-- MAIN COLORS -->
+ <color name="transparent">#00000000</color>
+ <color name="white">#FFFFFF</color>
+ <color name="white_transparent">#55FFFFFF</color>
+ <color name="grey">#5B5B5B</color>
+ <color name="grey_light">#999999</color>
+ <color name="grey_dark">#333333</color>
+ <color name="grey_transparent">#66999999</color>
+ <color name="blue">#2AA9E0</color>
+ <color name="blue_dark">#123C59</color>
+ <color name="blue_light">#AADCF2</color>
+ <color name="blue_light_transparent">#DBEAF0</color>
+ <color name="green">#6BC1A3</color>
+ <color name="green_dark">#17717A</color>
+ <color name="green_light">#A0D7C4</color>
+ <color name="green_light_transparent">#D8E8E2</color>
+ <color name="pink">#C1454A</color>
+ <color name="pink_dark">#823A3D</color>
+ <color name="pink_light">#F286B6</color>
+ <color name="pink_light_transparent">#F0DBE4</color>
+ <color name="red">#C3474C</color>
-
-</resources>
\ No newline at end of file
+</resources>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index c59b7cf..2c49b92 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,8 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <!-- ActionBar contentInsetStart -->
- <dimen name="actionbar_contentInsetStart">16dp</dimen>
- <!-- ActionBar height -->
- <dimen name="actionbar_size">56dip</dimen>
-</resources>
\ No newline at end of file
+ <!-- HEADER -->
+ <dimen name="header_big_height">100dp</dimen>
+ <dimen name="header_small_height">56dp</dimen>
+ <dimen name="header_big_text_size">34sp</dimen>
+ <dimen name="header_small_text_size">20sp</dimen>
+ <dimen name="header_padding">8sp</dimen>
+
+ <!-- MAIN -->
+ <dimen name="main_margin">32dp</dimen>
+ <dimen name="main_margin_small">20dp</dimen>
+ <dimen name="main_padding">32dp</dimen>
+ <dimen name="main_padding_small">20dp</dimen>
+ <dimen name="main_small_text_margin_top">43dp</dimen>
+ <dimen name="main_small_text_below_heading_margin">20dp</dimen>
+ <dimen name="main_button_margin_top">8dp</dimen>
+</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a3dd27a..089d5e9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -6,10 +6,13 @@
<string name="activity_diagnostics">Diagnostics</string>
<string name="activity_calibration">Calibration</string>
- <string name="msg_block">Cover the sensor area completely with your finger (the sensor area is shown in the image above), then press the OK button.</string>
- <string name="msg_reading">Checking...</string>
- <string name="msg_unblock">Remove your finger from the sensor area and press the OK button.</string>
- <string name="msg_cal">Calibrating...</string>
+ <string name="incompatible_device">Incompatible device</string>
+ <string name="device_cannot_run_calibration_tool">The calibration tool cannot be run on your Fairphone 2. Make sure your device is running the latest software update.</string>
+
+ <string name="msg_block">Cover the sensor area completely with your finger (the sensor area is shown in the image above), then press the Next button.</string>
+ <string name="msg_reading">Retrieving information from the proximity sensor…</string>
+ <string name="msg_unblock">Remove your finger from the sensor area and press the Next button.</string>
+ <string name="msg_cal">Calibrating…</string>
<string name="msg_calibration_success"><![CDATA[Calibration successful! Press the OK & Reboot button to finalize the calibration process and to reboot your Fairphone.]]></string>
<string name="msg_step_success">Successful</string>
<string name="msg_fail">Unsuccessful</string>
@@ -18,7 +21,7 @@
<string name="msg_fail_block">Something went wrong, please try again. Make sure you cover the sensor area completely.</string>
<string name="msg_fail_cal">Calibration unsuccessful, please check the device and try again.</string>
<string name="msg_fail_unlock">Something went wrong, please try again. Make sure to remove your finger from the sensor area and that the screen is clean.</string>
- <string name="msg_fail_write_sns">Encountering unexpected permission issue…</string>
+ <string name="msg_fail_write_sns">Something went wrong, please check that your device is up-to-date and try again.</string>
<string name='not_triggered'>Not triggered</string>
<string name='state'>State: </string>
@@ -26,11 +29,11 @@
<string name='block_value'>Block value: </string>
<string name='unblock_value'>Unlock value: </string>
- <string name="step_1">Step 1</string>
- <string name="step_2">Step 2</string>
- <string name="step_3">Step 3</string>
+ <string name="step_1">Step 1/3</string>
+ <string name="step_2">Step 2/3</string>
+ <string name="step_3">Step 3/3</string>
- <string name="Heading">One more thing...</string>
+ <string name="Heading">One more thing…</string>
<string name="greating">Proximity sensor calibration</string>
<string name="Text"><![CDATA[ <p>Fairphone OS now gives you the option to calibrate the proximity sensor - this improves the sensor behavior while making a call (screen going off/on).</p> <p>We recommend to calibrate the proximity sensor now to get the best experience - it\'s easy and done in a second!</p>]]></string>
<string name="next">Next</string>
@@ -44,9 +47,20 @@
<string name="Exit">Exit</string>
<string name="OK">OK</string>
<string name="cancel">Cancel</string>
+ <string name="go_to_updater">Check for updates</string>
<string name="ask_really_dont_show_title">Are you sure?</string>
<string name="ask_really_dont_show_text"><![CDATA[Calibrating the proximity sensor is easy and will improve the call experience. <it>You can calibrate the proximity sensor at a later time in Settings → Maintenance → Proximity Sensor Tool</it>.]]></string>
<string name="preference_successfully_calibrated" translatable="false">preference_successfully_calibrated</string>
<string name="NotificationTitle">Finalizing Update</string>
+ <!-- FRAGMENT TAGS -->
+ <string name="fragment_tag_incompatible_device_dialog" translatable="false">incompatible_device</string>
+
+ <!-- SHARED PREFERENCES -->
+ <string name="preference_pending_calibration" translatable="false">preference_pending_calibration</string>
+
+ <!-- EXTERNAL PACKAGES AND ACTIVITIES -->
+ <string name="package_fairphone_updater" translatable="false">com.fairphone.updater</string>
+ <string name="activity_fairphone_updater_check_for_updates" translatable="false">com.fairphone.updater.FairphoneUpdater</string>
+
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c531199..737a2c3 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,9 +1,204 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
+ <style name="AppTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
<!-- Customize your theme here. -->
- <item name="colorPrimary">@color/colorPrimary</item>
- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
- <item name="colorAccent">@color/colorAccent</item>
+ <item name="android:colorPrimary">@color/theme_primary</item>
+ <item name="android:colorPrimaryDark">@color/theme_primary_dark</item>
+ <item name="android:colorAccent">@color/theme_accent</item>
+ <item name="android:statusBarColor">@color/theme_primary_dark</item>
</style>
-</resources>
\ No newline at end of file
+
+ <!-- BUTTONS -->
+ <style name="Button" parent="@android:style/Widget.Button">
+ <item name="android:background">@drawable/button_grey_background</item>
+ <item name="android:textColor">@color/white</item>
+ <item name="android:textSize">24sp</item>
+ <item name="android:paddingTop">15dp</item>
+ <item name="android:paddingBottom">15dp</item>
+ <item name="android:paddingRight">15dp</item>
+ <item name="android:paddingLeft">15dp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:textAllCaps">true</item>
+ </style>
+
+ <style name="ButtonWhiteBlue" parent="@style/Button">
+ <item name="android:background">@drawable/button_blue_background</item>
+ <item name="android:textColor">@color/white</item>
+ </style>
+
+ <style name="ButtonWhitePink" parent="@style/Button">
+ <item name="android:background">@drawable/button_pink_transparent_background</item>
+ <item name="android:textColor">@color/white</item>
+ </style>
+
+ <!-- TEXT REGULAR -->
+ <style name="TextRegular">
+ <item name="android:fontFamily">sans-serif</item>
+ </style>
+
+ <style name="TextRegular14" parent="@style/TextRegular">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="TextRegular16" parent="@style/TextRegular">
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextRegular14BlueLight" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/blue_light</item>
+ </style>
+
+ <style name="TextRegular14BlueDark" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/blue_dark</item>
+ </style>
+
+ <style name="TextRegular14GreenLight" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/green_light</item>
+ </style>
+
+ <style name="TextRegular14GreenDark" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/green_dark</item>
+ </style>
+
+ <style name="TextRegular14GreyLight" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/grey_light</item>
+ </style>
+
+ <style name="TextRegular14GreyDark" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/grey_dark</item>
+ </style>
+
+ <style name="TextRegular14PinkLight" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/pink_light</item>
+ </style>
+
+ <style name="TextRegular14PinkDark" parent="@style/TextRegular14">
+ <item name="android:textColor">@color/pink_dark</item>
+ </style>
+
+ <style name="TextRegular16BlueLight" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/blue_light</item>
+ </style>
+
+ <style name="TextRegular16BlueDark" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/blue_dark</item>
+ </style>
+
+ <style name="TextRegular16GreenLight" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/green_light</item>
+ </style>
+
+ <style name="TextRegular16GreenDark" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/green_dark</item>
+ </style>
+
+ <style name="TextRegular16GreyLight" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/grey_light</item>
+ </style>
+
+ <style name="TextRegular16GreyDark" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/grey_dark</item>
+ </style>
+
+ <style name="TextRegular16PinkLight" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/pink_light</item>
+ </style>
+
+ <style name="TextRegular16PinkDark" parent="@style/TextRegular16">
+ <item name="android:textColor">@color/pink_dark</item>
+ </style>
+
+ <!-- TEXT LIGHT -->
+ <style name="TextLight">
+ <item name="android:fontFamily">sans-serif-light</item>
+ </style>
+
+ <!-- TEXT BOLD -->
+ <style name="TextBold">
+ <item name="android:fontFamily">sans-serif</item>
+ <item name="android:textStyle">bold</item>
+ </style>
+
+ <style name="TextBold14" parent="@style/TextBold">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="TextBold16" parent="@style/TextBold">
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextBold14BlueLight" parent="@style/TextBold14">
+ <item name="android:textColor">@color/blue_light</item>
+ </style>
+
+ <style name="TextBold14BlueDark" parent="@style/TextBold14">
+ <item name="android:textColor">@color/blue_dark</item>
+ </style>
+
+ <style name="TextBold14GreenLight" parent="@style/TextBold14">
+ <item name="android:textColor">@color/green_light</item>
+ </style>
+
+ <style name="TextBold14GreenDark" parent="@style/TextBold14">
+ <item name="android:textColor">@color/green_dark</item>
+ </style>
+
+ <style name="TextBold14GreyLight" parent="@style/TextBold14">
+ <item name="android:textColor">@color/grey_light</item>
+ </style>
+
+ <style name="TextBold14GreyDark" parent="@style/TextBold14">
+ <item name="android:textColor">@color/grey_dark</item>
+ </style>
+
+ <style name="TextBold14PinkLight" parent="@style/TextBold14">
+ <item name="android:textColor">@color/pink_light</item>
+ </style>
+
+ <style name="TextBold14PinkDark" parent="@style/TextBold14">
+ <item name="android:textColor">@color/pink_dark</item>
+ </style>
+
+ <style name="TextBold16BlueLight" parent="@style/TextBold16">
+ <item name="android:textColor">@color/blue_light</item>
+ </style>
+
+ <style name="TextBold16BlueDark" parent="@style/TextBold16">
+ <item name="android:textColor">@color/blue_dark</item>
+ </style>
+
+ <style name="TextBold16GreenLight" parent="@style/TextBold16">
+ <item name="android:textColor">@color/green_light</item>
+ </style>
+
+ <style name="TextBold16GreenDark" parent="@style/TextBold16">
+ <item name="android:textColor">@color/green_dark</item>
+ </style>
+
+ <style name="TextBold16GreyLight" parent="@style/TextBold16">
+ <item name="android:textColor">@color/grey_light</item>
+ </style>
+
+ <style name="TextBold16GreyDark" parent="@style/TextBold16">
+ <item name="android:textColor">@color/grey_dark</item>
+ </style>
+
+ <style name="TextBold16PinkLight" parent="@style/TextBold16">
+ <item name="android:textColor">@color/pink_light</item>
+ </style>
+
+ <style name="TextBold16PinkDark" parent="@style/TextBold16">
+ <item name="android:textColor">@color/pink_dark</item>
+ </style>
+
+ <!-- TITLE (HEADER) -->
+ <style name="TitleLight" parent="TextLight">
+ <item name="android:textSize">@dimen/header_big_text_size</item>
+ </style>
+
+ <style name="TitleLightPrimary" parent="TitleLight">
+ <item name="android:textColor">@color/theme_primary</item>
+ </style>
+
+</resources>
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 0c7fed7..96fc73c 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -18,10 +18,6 @@
<!--<item name="wifi_signal">@drawable/wifi_signal_teal</item>-->
<!--<item name="side_margin">@dimen/settings_side_margin</item>-->
- <!-- Redefine the ActionBar style for contentInsetStart -->
- <item name="android:actionBarStyle">@style/Theme.ActionBar</item>
- <item name="@*android:actionBarSize">@dimen/actionbar_size</item>
-
<!--<item name="switchBarTheme">@style/Theme.SwitchBar.Settings</item>-->
<item name="preferenceBackgroundColor">@drawable/preference_background</item>
@@ -38,11 +34,6 @@
<!--<item name="@android:timePickerStyle">@style/Widget.TimePicker</item>-->
</style>
-
- <style name="Theme.ActionBar" parent="@android:style/Widget.Material.Light.ActionBar.Solid">
- <item name="android:contentInsetStart">@dimen/actionbar_contentInsetStart</item>
- </style>
-
<style name="Theme.DialogWhenLarge" parent="@android:style/Theme.Material.Light.DialogWhenLarge">
<!-- Explicitly override the background color. -->
<item name="android:colorBackground">@android:color/white</item>
@@ -54,9 +45,6 @@
<!-- Used by controls, e.g. CheckBox, ProgressBar, etc. -->
<item name="android:colorAccent">@color/theme_accent</item>
- <!-- Redefine the ActionBar style for contentInsetStart -->
- <item name="android:actionBarStyle">@style/Theme.ActionBar</item>
-
<item name="preferenceBackgroundColor">@drawable/preference_background</item>
</style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/build.gradle b/build.gradle
index a4012cf..aff4f41 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.0-alpha4'
+ classpath 'com.android.tools.build:gradle:2.1.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files