Update app icon, use AppAuth library for Oauth (instead of Play Services), fix vibrate/silent feature on pre-6.0
|
@ -1,3 +1,9 @@
|
|||
1.4.1:
|
||||
- Updated app icon (thanks Symbolisch)
|
||||
- Changed MediNET Oauth method from Play Services to open-source library AppAuth
|
||||
- Fix set to vibrate/silent feature on pre-Android 6.0 devices
|
||||
- App now requires Android 4.1+ (was 4.0+)
|
||||
|
||||
1.4.0:
|
||||
- Fix alarm icon appearing in the status bar when Daily Reminder is enabled
|
||||
- Increase fidelity of the default gong sound
|
||||
|
|
|
@ -1,31 +1,37 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.1'
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
jcenter()
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion '24.0.2'
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.2'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 24
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 26
|
||||
|
||||
versionCode 140
|
||||
versionName "1.4.0"
|
||||
versionCode 141
|
||||
versionName "1.4.1"
|
||||
|
||||
jackOptions {
|
||||
enabled true
|
||||
}
|
||||
|
||||
applicationId "sh.ftp.rocketninelabs.meditationassistant"
|
||||
manifestPlaceholders = [
|
||||
'appAuthRedirectScheme': applicationId
|
||||
]
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
|
@ -33,6 +39,12 @@ android {
|
|||
abortOnError false
|
||||
}
|
||||
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
output.outputFile = new File(
|
||||
|
@ -58,41 +70,56 @@ android {
|
|||
|
||||
productFlavors {
|
||||
free {
|
||||
applicationId "sh.ftp.rocketninelabs.meditationassistant"
|
||||
buildConfigField "String", "GOOGLEOAUTHKEY", "\"163346957857.apps.googleusercontent.com\""
|
||||
}
|
||||
|
||||
full {
|
||||
buildConfigField "String", "GOOGLEOAUTHKEY", "\"153054147563.apps.googleusercontent.com\""
|
||||
|
||||
applicationId "sh.ftp.rocketninelabs.meditationassistant.full"
|
||||
manifestPlaceholders = [
|
||||
'appAuthRedirectScheme': applicationId
|
||||
]
|
||||
}
|
||||
|
||||
opensource {
|
||||
applicationId "sh.ftp.rocketninelabs.meditationassistant.opensource"
|
||||
|
||||
buildConfigField "String", "GOOGLEOAUTHKEY", "\"821225341172-64l3l6kdk9ull9lc7fjgeuuu7nee7pb9.apps.googleusercontent.com\""
|
||||
delete('google-services.json')
|
||||
|
||||
applicationId "sh.ftp.rocketninelabs.meditationassistant.opensource"
|
||||
manifestPlaceholders = [
|
||||
'appAuthRedirectScheme': applicationId
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:24.2.1'
|
||||
freeCompile 'com.google.android.gms:play-services-base:9.6.1'
|
||||
fullCompile 'com.google.android.gms:play-services-base:9.6.1'
|
||||
freeCompile 'com.google.android.gms:play-services-identity:9.6.1'
|
||||
fullCompile 'com.google.android.gms:play-services-identity:9.6.1'
|
||||
freeCompile 'com.google.android.gms:play-services-analytics:9.6.1'
|
||||
fullCompile 'com.google.android.gms:play-services-analytics:9.6.1'
|
||||
freeCompile 'com.google.android.gms:play-services-wearable:9.6.1'
|
||||
fullCompile 'com.google.android.gms:play-services-wearable:9.6.1'
|
||||
freeCompile 'com.google.android.gms:play-services-appinvite:9.6.1'
|
||||
fullCompile 'com.google.android.gms:play-services-appinvite:9.6.1'
|
||||
freeCompile 'com.google.android.gms:play-services-fitness:9.6.1'
|
||||
fullCompile 'com.google.android.gms:play-services-fitness:9.6.1'
|
||||
freeCompile 'com.google.android.gms:play-services-ads:9.6.1'
|
||||
compile "com.android.support:support-compat:26.1.0"
|
||||
compile "com.android.support:support-core-utils:26.1.0"
|
||||
compile "com.android.support:support-core-ui:26.1.0"
|
||||
compile "com.android.support:support-media-compat:26.1.0"
|
||||
compile "com.android.support:support-fragment:26.1.0"
|
||||
compile "com.android.support:recyclerview-v7:26.1.0"
|
||||
compile "com.android.support:design:26.1.0"
|
||||
compile "net.openid:appauth:0.7.0"
|
||||
compile "com.squareup.okio:okio:1.13.0"
|
||||
|
||||
freeCompile 'com.google.android.gms:play-services-base:11.4.2'
|
||||
fullCompile 'com.google.android.gms:play-services-base:11.4.2'
|
||||
freeCompile 'com.google.android.gms:play-services-analytics:11.4.2'
|
||||
fullCompile 'com.google.android.gms:play-services-analytics:11.4.2'
|
||||
//freeCompile 'com.google.android.gms:play-services-wearable:11.4.2'
|
||||
//fullCompile 'com.google.android.gms:play-services-wearable:11.4.2'
|
||||
freeCompile 'com.google.android.gms:play-services-appinvite:11.4.2'
|
||||
fullCompile 'com.google.android.gms:play-services-appinvite:11.4.2'
|
||||
freeCompile 'com.google.android.gms:play-services-fitness:11.4.2'
|
||||
fullCompile 'com.google.android.gms:play-services-fitness:11.4.2'
|
||||
freeCompile 'com.google.android.gms:play-services-ads:11.4.2'
|
||||
//noinspection GradleDynamicVersion
|
||||
compile 'ch.acra:acra:4.9.0'
|
||||
compile 'com.github.amlcurran.showcaseview:library:5.4.3'
|
||||
compile 'com.nononsenseapps:filepicker:3.0.0'
|
||||
compile 'com.nononsenseapps:filepicker:4.1.0'
|
||||
//wearApp project(':MeditationAssistantWear')
|
||||
// TODO: Uncomment when Wear app is ready
|
||||
compile 'com.android.support:recyclerview-v7:24.2.1'
|
||||
}
|
||||
}
|
|
@ -183,10 +183,6 @@
|
|||
|
||||
-keep,allowshrinking,allowoptimization class * { <methods>; }
|
||||
|
||||
-keepclasseswithmembernames,allowshrinking class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembers,allowshrinking class * {
|
||||
public <init>(android.content.Context,android.util.AttributeSet);
|
||||
public <init>(android.content.Context,android.util.AttributeSet,int);
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<application
|
||||
|
@ -69,6 +67,15 @@
|
|||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="sh.ftp.rocketninelabs.meditationassistant.MainActivity"/>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="sh.ftp.rocketninelabs.meditationassistant.AuthResultActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|screenSize|orientation"
|
||||
android:label="@string/signInToMediNET"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="sh.ftp.rocketninelabs.meditationassistant.MainActivity"/>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="sh.ftp.rocketninelabs.meditationassistant.MediNETActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|screenSize|orientation"
|
||||
|
|
|
@ -141,13 +141,13 @@ public class AboutActivity extends Activity {
|
|||
public void openHowToMeditate(View view) {
|
||||
startActivity(new Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://medinet.ftp.sh/howtomeditate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
Uri.parse("https://medinet.rocketnine.space/howtomeditate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
public void openTranslate(View view) {
|
||||
startActivity(new Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://medinet.ftp.sh/translate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
Uri.parse("https://medinet.rocketnine.space/translate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
public void openDonate(View view) {
|
||||
|
@ -192,7 +192,7 @@ public class AboutActivity extends Activity {
|
|||
} else {
|
||||
startActivity(new Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://medinet.ftp.sh/donate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
Uri.parse("https://rocketnine.space/donate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import net.openid.appauth.connectivity.ConnectionBuilder;
|
||||
import net.openid.appauth.connectivity.DefaultConnectionBuilder;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Reads and validates the demo app configuration from `res/raw/auth_config.json`. Configuration
|
||||
* changes are detected by comparing the hash of the last known configuration to the read
|
||||
* configuration. When a configuration change is detected, the app state is reset.
|
||||
*/
|
||||
public final class AuthConfiguration {
|
||||
|
||||
private static final String TAG = "Configuration";
|
||||
|
||||
private static final String PREFS_NAME = "config";
|
||||
private static final String KEY_LAST_HASH = "lastHash";
|
||||
|
||||
private static WeakReference<AuthConfiguration> sInstance = new WeakReference<>(null);
|
||||
|
||||
private final Context mContext;
|
||||
private final SharedPreferences mPrefs;
|
||||
private final Resources mResources;
|
||||
|
||||
private JSONObject mConfigJson;
|
||||
private String mConfigError;
|
||||
|
||||
private String mClientId;
|
||||
private String mScope;
|
||||
private Uri mRedirectUri;
|
||||
private Uri mDiscoveryUri;
|
||||
private Uri mAuthEndpointUri;
|
||||
private Uri mTokenEndpointUri;
|
||||
private Uri mRegistrationEndpointUri;
|
||||
|
||||
public static AuthConfiguration getInstance(Context context) {
|
||||
AuthConfiguration config = sInstance.get();
|
||||
if (config == null) {
|
||||
config = new AuthConfiguration(context);
|
||||
sInstance = new WeakReference<AuthConfiguration>(config);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public AuthConfiguration(Context context) {
|
||||
mContext = context;
|
||||
mPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
mResources = context.getResources();
|
||||
|
||||
try {
|
||||
readConfiguration();
|
||||
} catch (InvalidConfigurationException ex) {
|
||||
mConfigError = ex.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the current configuration is valid.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return mConfigError == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of the configuration error, if the configuration is invalid.
|
||||
*/
|
||||
@Nullable
|
||||
public String getConfigurationError() {
|
||||
return mConfigError;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public String getClientId() {
|
||||
return mClientId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getScope() {
|
||||
return mScope;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Uri getRedirectUri() {
|
||||
return mRedirectUri;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Uri getDiscoveryUri() {
|
||||
return mDiscoveryUri;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Uri getAuthEndpointUri() {
|
||||
return mAuthEndpointUri;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Uri getTokenEndpointUri() {
|
||||
return mTokenEndpointUri;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Uri getRegistrationEndpointUri() {
|
||||
return mRegistrationEndpointUri;
|
||||
}
|
||||
|
||||
public ConnectionBuilder getConnectionBuilder() {
|
||||
return DefaultConnectionBuilder.INSTANCE;
|
||||
}
|
||||
|
||||
private void readConfiguration() throws InvalidConfigurationException {
|
||||
mClientId = ""; // TODO: blank?
|
||||
mScope = "openid email profile";
|
||||
mRedirectUri = Uri.parse("https://medinet.rocketnine.space/oauth");
|
||||
|
||||
if (!isRedirectUriRegistered()) {
|
||||
throw new InvalidConfigurationException(
|
||||
"redirect_uri is not handled by any activity in this app! "
|
||||
+ "Ensure that the appAuthRedirectScheme in your build.gradle file "
|
||||
+ "is correctly configured, or that an appropriate intent filter "
|
||||
+ "exists in your app manifest.");
|
||||
}
|
||||
|
||||
/*if (getConfigString("discovery_uri") == null) {
|
||||
mAuthEndpointUri = getRequiredConfigWebUri("authorization_endpoint_uri");
|
||||
|
||||
mTokenEndpointUri = getRequiredConfigWebUri("token_endpoint_uri");
|
||||
|
||||
if (mClientId == null) {
|
||||
mRegistrationEndpointUri = getRequiredConfigWebUri("registration_endpoint_uri");
|
||||
}
|
||||
} else {
|
||||
mDiscoveryUri = getRequiredConfigWebUri("discovery_uri");
|
||||
}*/
|
||||
mDiscoveryUri = Uri.parse("");
|
||||
}
|
||||
|
||||
private boolean isRedirectUriRegistered() {
|
||||
// ensure that the redirect URI declared in the configuration is handled by some activity
|
||||
// in the app, by querying the package manager speculatively
|
||||
Intent redirectIntent = new Intent();
|
||||
redirectIntent.setPackage(mContext.getPackageName());
|
||||
redirectIntent.setAction(Intent.ACTION_VIEW);
|
||||
redirectIntent.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
redirectIntent.setData(mRedirectUri);
|
||||
|
||||
return !mContext.getPackageManager().queryIntentActivities(redirectIntent, 0).isEmpty();
|
||||
}
|
||||
|
||||
public static final class InvalidConfigurationException extends Exception {
|
||||
InvalidConfigurationException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
InvalidConfigurationException(String reason, Throwable cause) {
|
||||
super(reason, cause);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.MainThread;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.WorkerThread;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.openid.appauth.AppAuthConfiguration;
|
||||
import net.openid.appauth.AuthState;
|
||||
import net.openid.appauth.AuthorizationException;
|
||||
import net.openid.appauth.AuthorizationResponse;
|
||||
import net.openid.appauth.AuthorizationService;
|
||||
import net.openid.appauth.AuthorizationServiceDiscovery;
|
||||
import net.openid.appauth.ClientAuthentication;
|
||||
import net.openid.appauth.TokenRequest;
|
||||
import net.openid.appauth.TokenResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import okio.Okio;
|
||||
|
||||
/**
|
||||
* Displays the authorized state of the user. This activity is provided with the outcome of the
|
||||
* authorization flow, which it uses to negotiate the final authorized state,
|
||||
* by performing an authorization code exchange if necessary. After this, the activity provides
|
||||
* additional post-authorization operations if available, such as fetching user info and refreshing
|
||||
* access tokens.
|
||||
*/
|
||||
public class AuthResultActivity extends Activity {
|
||||
MeditationAssistant ma = null;
|
||||
|
||||
private static final String KEY_USER_INFO = "userInfo";
|
||||
|
||||
private AuthorizationService mAuthService;
|
||||
private AuthStateManager mStateManager;
|
||||
private final AtomicReference<JSONObject> mUserInfoJson = new AtomicReference<>();
|
||||
private ExecutorService mExecutor;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mStateManager = AuthStateManager.getInstance(this);
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
AuthConfiguration config = AuthConfiguration.getInstance(this);
|
||||
|
||||
mAuthService = new AuthorizationService(
|
||||
this,
|
||||
new AppAuthConfiguration.Builder()
|
||||
.setConnectionBuilder(config.getConnectionBuilder())
|
||||
.build());
|
||||
|
||||
displayLoading("Restoring state...");
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
try {
|
||||
mUserInfoJson.set(new JSONObject(savedInstanceState.getString(KEY_USER_INFO)));
|
||||
} catch (JSONException ex) {
|
||||
Log.e("MA", "Failed to parse saved user info JSON, discarding", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
if (mExecutor.isShutdown()) {
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
if (mStateManager.getCurrent().isAuthorized()) {
|
||||
updateState();
|
||||
return;
|
||||
}
|
||||
|
||||
// the stored AuthState is incomplete, so check if we are currently receiving the result of
|
||||
// the authorization flow from the browser.
|
||||
AuthorizationResponse response = AuthorizationResponse.fromIntent(getIntent());
|
||||
AuthorizationException ex = AuthorizationException.fromIntent(getIntent());
|
||||
|
||||
if (response != null || ex != null) {
|
||||
mStateManager.updateAfterAuthorization(response, ex);
|
||||
}
|
||||
|
||||
if (response != null && response.authorizationCode != null) {
|
||||
// authorization code exchange is required
|
||||
mStateManager.updateAfterAuthorization(response, ex);
|
||||
exchangeAuthorizationCode(response);
|
||||
} else if (ex != null) {
|
||||
// TODO: handle failure "Authorization flow failed: " + ex.getMessage());
|
||||
} else {
|
||||
// TODO: handle failure No authorization state retained - reauthorization required");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle state) {
|
||||
// user info is retained to survive activity restarts, such as when rotating the
|
||||
// device or switching apps. This isn't essential, but it helps provide a less
|
||||
// jarring UX when these events occur - data does not just disappear from the view.
|
||||
if (mUserInfoJson.get() != null) {
|
||||
state.putString(KEY_USER_INFO, mUserInfoJson.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mAuthService.dispose();
|
||||
mExecutor.shutdownNow();
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void displayLoading(String message) {
|
||||
Log.d("MA", "Auth: " + message);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void updateState() {
|
||||
AuthState state = mStateManager.getCurrent();
|
||||
|
||||
if (state.getAccessToken() == null) {
|
||||
Log.d("MA", "Access token was null: ");
|
||||
// TODO: Handle auth failure, prompt to retry
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Long expiresAt = state.getAccessTokenExpirationTime();
|
||||
if (expiresAt != null && expiresAt < System.currentTimeMillis()) {
|
||||
refreshAccessToken();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("MA", "Got token");
|
||||
getMeditationAssistant().getMediNET().signInWithAuthToken(state.getAccessToken());
|
||||
finish();
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void refreshAccessToken() {
|
||||
displayLoading("Refreshing access token");
|
||||
performTokenRequest(
|
||||
mStateManager.getCurrent().createTokenRefreshRequest(),
|
||||
this::handleAccessTokenResponse);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void exchangeAuthorizationCode(AuthorizationResponse authorizationResponse) {
|
||||
displayLoading("Exchanging authorization code");
|
||||
performTokenRequest(
|
||||
authorizationResponse.createTokenExchangeRequest(),
|
||||
this::handleCodeExchangeResponse);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void performTokenRequest(
|
||||
TokenRequest request,
|
||||
AuthorizationService.TokenResponseCallback callback) {
|
||||
ClientAuthentication clientAuthentication;
|
||||
try {
|
||||
clientAuthentication = mStateManager.getCurrent().getClientAuthentication();
|
||||
} catch (ClientAuthentication.UnsupportedAuthenticationMethod ex) {
|
||||
Log.d("MA", "Token request cannot be made, client authentication for the token "
|
||||
+ "endpoint could not be constructed (%s)", ex);
|
||||
// TODO handle failure Client authentication method is unsupported");
|
||||
return;
|
||||
}
|
||||
|
||||
mAuthService.performTokenRequest(
|
||||
request,
|
||||
clientAuthentication,
|
||||
callback);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void handleAccessTokenResponse(
|
||||
@Nullable TokenResponse tokenResponse,
|
||||
@Nullable AuthorizationException authException) {
|
||||
mStateManager.updateAfterTokenResponse(tokenResponse, authException);
|
||||
runOnUiThread(this::updateState);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void handleCodeExchangeResponse(
|
||||
@Nullable TokenResponse tokenResponse,
|
||||
@Nullable AuthorizationException authException) {
|
||||
|
||||
mStateManager.updateAfterTokenResponse(tokenResponse, authException);
|
||||
if (!mStateManager.getCurrent().isAuthorized()) {
|
||||
final String message = "Authorization Code exchange failed"
|
||||
+ ((authException != null) ? authException.error : "");
|
||||
|
||||
// WrongThread inference is incorrect for lambdas
|
||||
//noinspection WrongThread
|
||||
// TODO: Handle not authorized, show error
|
||||
} else {
|
||||
runOnUiThread(this::updateState);
|
||||
}
|
||||
}
|
||||
public MeditationAssistant getMeditationAssistant() {
|
||||
if (ma == null) {
|
||||
ma = (MeditationAssistant) this.getApplication();
|
||||
}
|
||||
return ma;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.annotation.AnyThread;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import net.openid.appauth.AuthState;
|
||||
import net.openid.appauth.AuthorizationException;
|
||||
import net.openid.appauth.AuthorizationResponse;
|
||||
import net.openid.appauth.RegistrationResponse;
|
||||
import net.openid.appauth.TokenResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* An example persistence mechanism for an {@link AuthState} instance.
|
||||
* This stores the instance in a shared preferences file, and provides thread-safe access and
|
||||
* mutation.
|
||||
*/
|
||||
public class AuthStateManager {
|
||||
|
||||
private static final AtomicReference<WeakReference<AuthStateManager>> INSTANCE_REF =
|
||||
new AtomicReference<>(new WeakReference<AuthStateManager>(null));
|
||||
|
||||
private static final String TAG = "AuthStateManager";
|
||||
|
||||
private static final String STORE_NAME = "AuthState";
|
||||
private static final String KEY_STATE = "state";
|
||||
|
||||
private final SharedPreferences mPrefs;
|
||||
private final ReentrantLock mPrefsLock;
|
||||
private final AtomicReference<AuthState> mCurrentAuthState;
|
||||
|
||||
@AnyThread
|
||||
public static AuthStateManager getInstance(@NonNull Context context) {
|
||||
AuthStateManager manager = INSTANCE_REF.get().get();
|
||||
if (manager == null) {
|
||||
manager = new AuthStateManager(context.getApplicationContext());
|
||||
INSTANCE_REF.set(new WeakReference<>(manager));
|
||||
}
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
private AuthStateManager(Context context) {
|
||||
mPrefs = context.getSharedPreferences(STORE_NAME, Context.MODE_PRIVATE);
|
||||
mPrefsLock = new ReentrantLock();
|
||||
mCurrentAuthState = new AtomicReference<>();
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AuthState getCurrent() {
|
||||
if (mCurrentAuthState.get() != null) {
|
||||
return mCurrentAuthState.get();
|
||||
}
|
||||
|
||||
AuthState state = readState();
|
||||
if (mCurrentAuthState.compareAndSet(null, state)) {
|
||||
return state;
|
||||
} else {
|
||||
return mCurrentAuthState.get();
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AuthState replace(@NonNull AuthState state) {
|
||||
writeState(state);
|
||||
mCurrentAuthState.set(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AuthState updateAfterAuthorization(
|
||||
@Nullable AuthorizationResponse response,
|
||||
@Nullable AuthorizationException ex) {
|
||||
AuthState current = getCurrent();
|
||||
current.update(response, ex);
|
||||
return replace(current);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AuthState updateAfterTokenResponse(
|
||||
@Nullable TokenResponse response,
|
||||
@Nullable AuthorizationException ex) {
|
||||
AuthState current = getCurrent();
|
||||
current.update(response, ex);
|
||||
return replace(current);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AuthState updateAfterRegistration(
|
||||
RegistrationResponse response,
|
||||
AuthorizationException ex) {
|
||||
AuthState current = getCurrent();
|
||||
if (ex != null) {
|
||||
return current;
|
||||
}
|
||||
|
||||
current.update(response);
|
||||
return replace(current);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
private AuthState readState() {
|
||||
mPrefsLock.lock();
|
||||
try {
|
||||
String currentState = mPrefs.getString(KEY_STATE, null);
|
||||
if (currentState == null) {
|
||||
return new AuthState();
|
||||
}
|
||||
|
||||
try {
|
||||
return AuthState.jsonDeserialize(currentState);
|
||||
} catch (JSONException ex) {
|
||||
Log.w(TAG, "Failed to deserialize stored auth state - discarding");
|
||||
return new AuthState();
|
||||
}
|
||||
} finally {
|
||||
mPrefsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
private void writeState(@Nullable AuthState state) {
|
||||
mPrefsLock.lock();
|
||||
try {
|
||||
SharedPreferences.Editor editor = mPrefs.edit();
|
||||
if (state == null) {
|
||||
editor.remove(KEY_STATE);
|
||||
} else {
|
||||
editor.putString(KEY_STATE, state.jsonSerializeString());
|
||||
}
|
||||
|
||||
if (!editor.commit()) {
|
||||
throw new IllegalStateException("Failed to write state to shared prefs");
|
||||
}
|
||||
} finally {
|
||||
mPrefsLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -341,7 +341,7 @@ public class CompleteActivity extends Activity {
|
|||
|
||||
public void postMediNET(View view) {
|
||||
if (getMeditationAssistant().getMediNETKey() == "") {
|
||||
getMeditationAssistant().showSignInDialog(this);
|
||||
getMeditationAssistant().startAuth(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public class JavaScriptInterface implements JavascriptCallback {
|
|||
MeditationAssistant ma = (MeditationAssistant) this.activity
|
||||
.getApplication();
|
||||
this.activity.finish();
|
||||
ma.getMediNET().askToSignIn();
|
||||
ma.startAuth(false);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.media.AudioManager;
|
|||
import android.media.MediaPlayer;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.ListPreference;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -63,7 +62,6 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
public static int ID_DELAY = 77702;
|
||||
public static int ID_INTERVAL = 77701;
|
||||
public static int ID_END = 77703;
|
||||
private static final int PERMISSION_REQUEST_GET_ACCOUNTS = 3001;
|
||||
|
||||
public MeditationAssistant ma = null;
|
||||
SharedPreferences.OnSharedPreferenceChangeListener sharedPrefslistener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||
|
@ -494,7 +492,7 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
case DialogInterface.BUTTON_POSITIVE:
|
||||
startActivity(new Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://medinet.ftp.sh/translate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
Uri.parse("https://medinet.rocketnine.space/translate")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
break;
|
||||
|
||||
|
@ -2467,14 +2465,8 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
)
|
||||
)
|
||||
.setTitle(
|
||||
getString(R.string.signOutOfMediNETConfirmTitle))
|
||||
.setMessage(
|
||||
String.format(
|
||||
getString(R.string.signOutOfMediNETConfirm),
|
||||
getMeditationAssistant()
|
||||
.getMediNETProvider()
|
||||
)
|
||||
)
|
||||
getString(R.string.signOut))
|
||||
.setMessage(getString(R.string.signOutOfMediNETConfirmTitle))
|
||||
.setPositiveButton(getString(R.string.signOut),
|
||||
dialogClickListener)
|
||||
.setNegativeButton(getString(R.string.cancel),
|
||||
|
@ -2486,15 +2478,7 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
}
|
||||
|
||||
public void askToSignIn() {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.GET_ACCOUNTS)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{Manifest.permission.GET_ACCOUNTS},
|
||||
PERMISSION_REQUEST_GET_ACCOUNTS);
|
||||
} else {
|
||||
getMeditationAssistant().getMediNET().askToSignIn();
|
||||
}
|
||||
getMeditationAssistant().startAuth(false);
|
||||
}
|
||||
|
||||
public void stopMediaPlayer() {
|
||||
|
@ -2548,49 +2532,4 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
public void onShowcaseViewTouchBlocked(MotionEvent motionEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
String permissions[], int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PERMISSION_REQUEST_GET_ACCOUNTS: {
|
||||
if ((grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) || !ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.GET_ACCOUNTS)) {
|
||||
getMeditationAssistant().getMediNET().askToSignIn();
|
||||
} else {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setIcon(
|
||||
getResources()
|
||||
.getDrawable(
|
||||
getTheme()
|
||||
.obtainStyledAttributes(
|
||||
getMeditationAssistant()
|
||||
.getMATheme(true),
|
||||
new int[]{R.attr.actionIconSettings}
|
||||
)
|
||||
.getResourceId(0, 0)
|
||||
)
|
||||
)
|
||||
.setTitle(getString(R.string.permissionRequest))
|
||||
.setMessage(
|
||||
getString(R.string.permissionRequestAccounts))
|
||||
.setPositiveButton(getString(R.string.tryAgain),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
askToSignIn();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getString(R.string.deny),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
getMeditationAssistant().getMediNET().askToSignIn();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ import java.util.Calendar;
|
|||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
/**
|
||||
* Created by root on 11/2/13.
|
||||
*/
|
||||
public class MediNET {
|
||||
public static Integer version = 5;
|
||||
public static Integer version = 6;
|
||||
// API v1-5 was used on pre Android 4.1 (discontinued) releases
|
||||
// API v6 signifies non-discontinued (1.4.1+, Android 4.1+) app version
|
||||
|
||||
public String status = "disconnected";
|
||||
public String result = "";
|
||||
public MainActivity activity;
|
||||
|
@ -71,46 +71,6 @@ public class MediNET {
|
|||
return String.valueOf(hours) + ":" + String.format("%02d", minutes);
|
||||
}
|
||||
|
||||
public void askToSignIn() {
|
||||
/*if (activity == null || activity.stopped) {
|
||||
Log.d("MeditationAssistant",
|
||||
"MainActivity null or stopped, restarting... Stopped: "
|
||||
+ activity.stopped.toString());*/
|
||||
if (activity == null) {
|
||||
Intent openActivity = new Intent(getMeditationAssistant()
|
||||
.getApplicationContext(), MainActivity.class);
|
||||
openActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
openActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
handler.postDelayed(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d("MeditationAssistant",
|
||||
"Open MainActivity runnable is now running...");
|
||||
askToSignIn();
|
||||
}
|
||||
}, 400);
|
||||
|
||||
getMeditationAssistant().getApplicationContext().startActivity(
|
||||
openActivity);
|
||||
return;
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (activity == null) {
|
||||
Log.d("MeditationAssistant",
|
||||
"askToSignIn activity is null, returning...");
|
||||
return;
|
||||
}
|
||||
getMeditationAssistant().showSignInDialog(activity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void browseTo(MainActivity act, String page) {
|
||||
activity = act;
|
||||
browsetopage = page;
|
||||
|
@ -129,7 +89,7 @@ public class MediNET {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
askToSignIn();
|
||||
getMeditationAssistant().startAuth(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +110,7 @@ public class MediNET {
|
|||
}
|
||||
|
||||
if (getMeditationAssistant().getMediNETKey().equals("")) {
|
||||
askToSignIn();
|
||||
getMeditationAssistant().startAuth(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ public class MediNETActivity extends Activity {
|
|||
private String provider = "";
|
||||
private MeditationAssistant ma = null;
|
||||
private Handler handler = new Handler();
|
||||
private boolean signing_in = false;
|
||||
private boolean hide_refresh = false;
|
||||
|
||||
public static Intent newEmailIntent(Context context, String address, String subject, String body, String cc) {
|
||||
|
@ -57,7 +56,7 @@ public class MediNETActivity extends Activity {
|
|||
TimeZone tz = TimeZone.getDefault();
|
||||
Date now = new Date();
|
||||
|
||||
return "https://medinet.ftp.sh/client_android.php?v="
|
||||
return "https://medinet.rocketnine.space/client_android.php?v="
|
||||
+ MediNET.version.toString() + "&avn="
|
||||
+ String.valueOf(getMeditationAssistant().getMAAppVersionNumber()) + "&page=" + page + "&th="
|
||||
+ ma.getMAThemeString() + "&tz="
|
||||
|
@ -68,20 +67,8 @@ public class MediNETActivity extends Activity {
|
|||
public void goTo(String go_to) {
|
||||
String url;
|
||||
|
||||
if (go_to.equals("Google") || go_to.equals("Facebook")
|
||||
|| go_to.equals("Twitter") || go_to.equals("AOL")
|
||||
|| go_to.equals("OpenID") || go_to.equals("Live")
|
||||
|| go_to.equals("LinkedIn")) {
|
||||
setTitle(String.format(getString(R.string.signInWithProvider),
|
||||
go_to));
|
||||
url = "https://medinet.ftp.sh/client_android_login.php?v="
|
||||
+ MediNET.version.toString() + "&avn="
|
||||
+ String.valueOf(getMeditationAssistant().getMAAppVersionNumber()) + "&provider=" + go_to;
|
||||
provider = go_to;
|
||||
signing_in = true;
|
||||
} else if (go_to.equals("gpl") || go_to.equals("lgpl")) {
|
||||
if (go_to.equals("gpl") || go_to.equals("lgpl")) {
|
||||
setTitle("");
|
||||
signing_in = true;
|
||||
hide_refresh = true;
|
||||
|
||||
if (go_to.equals("gpl")) {
|
||||
|
@ -90,24 +77,30 @@ public class MediNETActivity extends Activity {
|
|||
url = "file:///android_asset/lgpl.html";
|
||||
}
|
||||
} else {
|
||||
if (go_to.equals("community")) {
|
||||
setTitle(getString(R.string.community));
|
||||
} else if (go_to.equals("sessions")) {
|
||||
setTitle(getString(R.string.sessions));
|
||||
} else if (go_to.equals("account")) {
|
||||
setTitle(getString(R.string.account));
|
||||
} else if (go_to.equals("forum")) {
|
||||
setTitle(getString(R.string.forum));
|
||||
} else if (go_to.equals("groups")) {
|
||||
setTitle(getString(R.string.groups));
|
||||
} else if (go_to.equals("signout")) {
|
||||
switch (go_to) {
|
||||
case "community":
|
||||
setTitle(getString(R.string.community));
|
||||
break;
|
||||
case "sessions":
|
||||
setTitle(getString(R.string.sessions));
|
||||
break;
|
||||
case "account":
|
||||
setTitle(getString(R.string.account));
|
||||
break;
|
||||
case "forum":
|
||||
setTitle(getString(R.string.forum));
|
||||
break;
|
||||
case "groups":
|
||||
setTitle(getString(R.string.groups));
|
||||
break;
|
||||
case "signout":
|
||||
|
||||
} else {
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
url = getPageUrl(go_to);
|
||||
signing_in = false;
|
||||
}
|
||||
|
||||
Log.d("MeditationAssistant", go_to + " - Going to: " + url);
|
||||
|
@ -200,12 +193,11 @@ public class MediNETActivity extends Activity {
|
|||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
if (Uri.parse(url) != null && Uri.parse(url).getHost() != null && Uri.parse(url).getHost().equals("medinet.ftp.sh")) {
|
||||
if (Uri.parse(url) != null && Uri.parse(url).getHost() != null && Uri.parse(url).getHost().equals("medinet.rocketnine.space")) {
|
||||
if (webView.getTitle() != null
|
||||
&& !webView.getTitle().trim().equals("")) {
|
||||
setTitle(webView.getTitle());
|
||||
}
|
||||
signing_in = url.contains("/hybridauth/");
|
||||
} else {
|
||||
/*
|
||||
* setTitle(String.format(getString(R.string.
|
||||
|
@ -219,36 +211,15 @@ public class MediNETActivity extends Activity {
|
|||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
/*getMeditationAssistant().setWebViewScale(
|
||||
(int) (100 * view.getScale()));*/
|
||||
Log.d("MeditationAssistant",
|
||||
"Signing_in: " + String.valueOf(signing_in) + " - "
|
||||
+ url
|
||||
);
|
||||
if (url != null && url.startsWith("mailto:")) {
|
||||
MailTo mt = MailTo.parse(url);
|
||||
Intent i = newEmailIntent(MediNETActivity.this, mt.getTo(), mt.getSubject(), mt.getBody(), mt.getCc());
|
||||
startActivity(i);
|
||||
view.reload();
|
||||
return true;
|
||||
/*} else if (url != null && Uri.parse(url) != null && Uri.parse(url).getHost() != null
|
||||
&& !Uri.parse(url).getHost()
|
||||
.equals("medinet.ftp.sh")
|
||||
&& webView.getUrl() != null
|
||||
&& Uri.parse(webView.getUrl()).getHost() != null && Uri.parse(webView.getUrl()).getHost()
|
||||
.equals("medinet.ftp.sh")
|
||||
&& !webView.getUrl().contains("provider=OpenID")) {
|
||||
|
||||
Log.d("MA", "!!!!!!!!!!!!!!!!! OPENING!!!");
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(url));
|
||||
startActivity(browserIntent);*/
|
||||
} else {
|
||||
view.loadUrl(url);
|
||||
}
|
||||
|
||||
Log.d("MA", Uri.parse(url).toString());
|
||||
Log.d("MA", Uri.parse(url).getHost());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -275,16 +246,7 @@ public class MediNETActivity extends Activity {
|
|||
// webView.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR);
|
||||
|
||||
if (activityOnCreate) {
|
||||
if (getIntent().hasExtra("provider")) {
|
||||
provider = getIntent().getStringExtra("provider");
|
||||
if (provider.equals("Google") || provider.equals("Facebook")
|
||||
|| provider.equals("Twitter") || provider.equals("AOL")
|
||||
|| provider.equals("OpenID") || provider.equals("Live")
|
||||
|| provider.equals("LinkedIn")) {
|
||||
signing_in = true;
|
||||
goTo(provider);
|
||||
}
|
||||
} else if (getIntent().hasExtra("page")
|
||||
if (getIntent().hasExtra("page")
|
||||
&& (getIntent().getStringExtra("page").equals("community")
|
||||
|| getIntent().getStringExtra("page").equals(
|
||||
"sessions")
|
||||
|
@ -296,7 +258,6 @@ public class MediNETActivity extends Activity {
|
|||
"forum")
|
||||
|| getIntent().getStringExtra("page").equals("gpl") || getIntent()
|
||||
.getStringExtra("page").equals("lgpl"))) {
|
||||
signing_in = false;
|
||||
goTo(getIntent().getStringExtra("page"));
|
||||
}
|
||||
} else {
|
||||
|
@ -414,12 +375,6 @@ public class MediNETActivity extends Activity {
|
|||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
if (signing_in) {
|
||||
menu.findItem(R.id.menuMediNET).setVisible(false);
|
||||
} else {
|
||||
menu.findItem(R.id.menuMediNET).setVisible(true);
|
||||
}
|
||||
|
||||
if (hide_refresh) {
|
||||
menu.findItem(R.id.refreshMediNET).setVisible(false);
|
||||
} else {
|
||||
|
@ -475,16 +430,7 @@ public class MediNETActivity extends Activity {
|
|||
getResources().getDrawable(
|
||||
android.R.drawable.background_holo_dark));*/
|
||||
webView.getSettings();
|
||||
if (signing_in) {
|
||||
webView.setBackgroundColor(Color.WHITE);
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT < 11) {
|
||||
webView.setBackgroundColor(Color.TRANSPARENT);
|
||||
} else {
|
||||
// Fix background flicker
|
||||
webView.setBackgroundColor(Color.argb(1, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
webView.setBackgroundColor(Color.argb(1, 0, 0, 0)); // TODO: Is this still necessary?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
@ -50,7 +51,7 @@ public class MediNETTask extends AsyncTask<MediNET, Integer, MediNET> {
|
|||
String appVersion = getMeditationAssistant().getMAAppVersion() + BuildConfig.FLAVOR;
|
||||
|
||||
if (this.nextURL == null) {
|
||||
this.nextURL = "https://medinet.ftp.sh/client_android.php?v="
|
||||
this.nextURL = "https://medinet.rocketnine.space/client_android.php?v="
|
||||
+ MediNET.version.toString() + "&av="
|
||||
+ appVersion + "&am="
|
||||
+ getMeditationAssistant().getMarketName() + "&avn="
|
||||
|
@ -59,7 +60,7 @@ public class MediNETTask extends AsyncTask<MediNET, Integer, MediNET> {
|
|||
}
|
||||
|
||||
if (action.equals("signin")) {
|
||||
this.nextURL = "https://medinet.ftp.sh/client_android_login_oauth2.php?v="
|
||||
this.nextURL = "https://medinet.rocketnine.space/client_android_login_oauth2.php?v="
|
||||
+ MediNET.version.toString() + "&av="
|
||||
+ appVersion + "&avn="
|
||||
+ String.valueOf(getMeditationAssistant().getMAAppVersionNumber()) + "&tz="
|
||||
|
@ -130,6 +131,11 @@ public class MediNETTask extends AsyncTask<MediNET, Integer, MediNET> {
|
|||
getMeditationAssistant().longToast(getMeditationAssistant().getString(R.string.sessionNotPosted));
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Log.i("MA", "Post data: " + getMeditationAssistant().getPostDataString(postData));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
@ -152,8 +158,8 @@ public class MediNETTask extends AsyncTask<MediNET, Integer, MediNET> {
|
|||
try {
|
||||
URL medinetURL = new URL(this.nextURL);
|
||||
medinetConnection = (HttpURLConnection) medinetURL.openConnection();
|
||||
|
||||
medinetConnection.setChunkedStreamingMode(0);
|
||||
medinetConnection.setReadTimeout(10000);
|
||||
medinetConnection.setConnectTimeout(15000);
|
||||
medinetConnection.setRequestMethod("POST");
|
||||
medinetConnection.setDoInput(true);
|
||||
medinetConnection.setDoOutput(true);
|
||||
|
@ -162,12 +168,11 @@ public class MediNETTask extends AsyncTask<MediNET, Integer, MediNET> {
|
|||
BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(os, "UTF-8"));
|
||||
writer.write(getMeditationAssistant().getPostDataString(postData));
|
||||
|
||||
medinetConnection.connect();
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
os.close();
|
||||
|
||||
medinetConnection.connect();
|
||||
int responseCode = medinetConnection.getResponseCode();
|
||||
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
|
@ -200,7 +205,7 @@ public class MediNETTask extends AsyncTask<MediNET, Integer, MediNET> {
|
|||
if (medinetConnection.getHeaderField("x-MediNET") != null) {
|
||||
if (medinetConnection.getHeaderField("x-MediNET")
|
||||
.equals("signin")) {
|
||||
this.medinet.askToSignIn();
|
||||
getMeditationAssistant().startAuth(false);
|
||||
} else {
|
||||
if (action.equals("signin") && medinetConnection.getHeaderField("x-MediNET-Key") != null) { /* Oauth2 sign in */
|
||||
Log.d("MeditationAssistant", "Header key: "
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerCallback;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
|
@ -23,11 +22,10 @@ import android.content.pm.PackageInfo;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Vibrator;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
|
@ -41,6 +39,11 @@ import android.view.WindowManager;
|
|||
import android.widget.ImageButton;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.openid.appauth.AuthorizationRequest;
|
||||
import net.openid.appauth.AuthorizationService;
|
||||
import net.openid.appauth.AuthorizationServiceConfiguration;
|
||||
import net.openid.appauth.ResponseTypeValues;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.annotation.ReportsCrashes;
|
||||
|
||||
|
@ -58,7 +61,7 @@ import java.util.Map;
|
|||
import java.util.TimeZone;
|
||||
|
||||
@ReportsCrashes(
|
||||
formUri = "https://medinet.ftp.sh/acra/acra.php"
|
||||
formUri = "https://medinet.rocketnine.space/acra/acra.php"
|
||||
)
|
||||
public class MeditationAssistant extends Application {
|
||||
|
||||
|
@ -66,6 +69,7 @@ public class MeditationAssistant extends Application {
|
|||
public static String ACTION_PRESET = "sh.ftp.rocketninelabs.meditationassistant.PRESET";
|
||||
public static String ACTION_REMINDER = "sh.ftp.rocketninelabs.meditationassistant.DAILY_NOTIFICATION";
|
||||
public static String ACTION_UPDATED = "sh.ftp.rocketninelabs.meditationassistant.DAILY_NOTIFICATION_UPDATED";
|
||||
public static String ACTION_AUTH = "sh.ftp.rocketninelabs.meditationassistant.AUTH";
|
||||
public static int REQUEST_FIT = 22;
|
||||
public static int MEDIA_DELAY = 1000;
|
||||
public Boolean debug_widgets = false; // Debug
|
||||
|
@ -227,7 +231,7 @@ public class MeditationAssistant extends Application {
|
|||
return mNotificationManager.getCurrentInterruptionFilter();
|
||||
}
|
||||
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getDurationFormatted() {
|
||||
|
@ -333,6 +337,37 @@ public class MeditationAssistant extends Application {
|
|||
return medinetprovider;
|
||||
}
|
||||
|
||||
public void startAuth(boolean showToast) {
|
||||
if (showToast) {
|
||||
shortToast(getString(R.string.signInToMediNET));
|
||||
}
|
||||
|
||||
AsyncTask.execute(() -> {
|
||||
AuthorizationServiceConfiguration serviceConfiguration = new AuthorizationServiceConfiguration(
|
||||
Uri.parse("https://accounts.google.com/o/oauth2/v2/auth") /* auth endpoint */,
|
||||
Uri.parse("https://www.googleapis.com/oauth2/v4/token") /* token endpoint */
|
||||
);
|
||||
|
||||
String clientId = BuildConfig.GOOGLEOAUTHKEY;
|
||||
Uri redirectUri = Uri.parse(BuildConfig.APPLICATION_ID + ":/oauth");
|
||||
AuthorizationRequest.Builder builder = new AuthorizationRequest.Builder(
|
||||
serviceConfiguration,
|
||||
clientId,
|
||||
ResponseTypeValues.CODE,
|
||||
redirectUri
|
||||
);
|
||||
builder.setScopes("profile");
|
||||
AuthorizationRequest request = builder.build();
|
||||
|
||||
AuthorizationService authorizationService = new AuthorizationService(MeditationAssistant.this);
|
||||
|
||||
authorizationService.performAuthorizationRequest(
|
||||
request,
|
||||
PendingIntent.getActivity(MeditationAssistant.this, 0, new Intent(MeditationAssistant.this, AuthResultActivity.class), 0),
|
||||
PendingIntent.getActivity(MeditationAssistant.this, 0, new Intent(MeditationAssistant.this, AuthResultActivity.class), 0));
|
||||
});
|
||||
}
|
||||
|
||||
public void recalculateMeditationStreak() {
|
||||
Calendar dayCalendar = new GregorianCalendar();
|
||||
Integer daysback = 0;
|
||||
|
@ -1005,203 +1040,6 @@ public class MeditationAssistant extends Application {
|
|||
notificationManager.notify(0, notification);
|
||||
}
|
||||
|
||||
public AlertDialog showSignInDialog(final Activity activity) {
|
||||
signin_activity = activity;
|
||||
|
||||
AccountManager accountManager = AccountManager
|
||||
.get(getApplicationContext());
|
||||
final Account[] accounts = accountManager
|
||||
.getAccountsByType("com.google");
|
||||
|
||||
final int size = accounts.length;
|
||||
|
||||
if (size > 0) {
|
||||
String[] names = new String[size + 1];
|
||||
int i = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
names[i] = accounts[i].name;
|
||||
}
|
||||
names[i] = getString(R.string.signInWithOpenID);
|
||||
|
||||
AlertDialog accountsAlertDialog = new AlertDialog.Builder(signin_activity)
|
||||
.setTitle(getString(R.string.signInWith))
|
||||
.setItems(names, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which != size) {
|
||||
AccountManager am = AccountManager.get(getApplicationContext());
|
||||
|
||||
if (am != null) {
|
||||
am.getAuthToken(accounts[which], AUTH_TOKEN_TYPE, null, signin_activity, new OnTokenAcquired(), new Handler(new Handler.Callback() {
|
||||
|
||||
public boolean handleMessage(Message msg) {
|
||||
Log.d("MeditationAssistant", "on error: " + msg.what);
|
||||
shortToast(getString(R.string.signInGoogleError));
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
showOpenIDSignInDialog(signin_activity);
|
||||
}
|
||||
}
|
||||
})
|
||||
.create();
|
||||
accountsAlertDialog.show();
|
||||
|
||||
return accountsAlertDialog;
|
||||
} else {
|
||||
return showOpenIDSignInDialog(signin_activity);
|
||||
}
|
||||
}
|
||||
|
||||
public AlertDialog showOpenIDSignInDialog(Activity activity) {
|
||||
if (alertDialog != null && alertDialog.getOwnerActivity() != null
|
||||
&& alertDialog.getOwnerActivity() == activity) {
|
||||
Log.d("MeditationAssistant",
|
||||
"Attempting to reuse MediNET sign in dialog");
|
||||
|
||||
try {
|
||||
if (!alertDialog.isShowing()) {
|
||||
alertDialog.show();
|
||||
}
|
||||
|
||||
Log.d("MeditationAssistant", "Reusing MediNET sign in dialog");
|
||||
return alertDialog;
|
||||
} catch (WindowManager.BadTokenException e) {
|
||||
// Activity is not in the foreground
|
||||
}
|
||||
}
|
||||
|
||||
int[] buttons = {R.id.btnGoogle, R.id.btnFacebook, R.id.btnAOL,
|
||||
R.id.btnTwitter, R.id.btnLive, R.id.btnOpenID};
|
||||
|
||||
View view = LayoutInflater.from(activity).inflate(
|
||||
R.layout.medinet_signin,
|
||||
(ViewGroup) activity.findViewById(R.id.medinetsignin_root));
|
||||
|
||||
for (int buttonid : buttons) {
|
||||
ImageButton btn = (ImageButton) view.findViewById(buttonid);
|
||||
|
||||
if (btn.getId() == R.id.btnGoogle) {
|
||||
if (!getMAThemeString().equals("dark")) {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_google_light));
|
||||
} else {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_google));
|
||||
}
|
||||
} else if (btn.getId() == R.id.btnFacebook) {
|
||||
if (!getMAThemeString().equals("dark")) {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_facebook_light));
|
||||
} else {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_facebook));
|
||||
}
|
||||
} else if (btn.getId() == R.id.btnAOL) {
|
||||
if (!getMAThemeString().equals("dark")) {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_aol_light));
|
||||
} else {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_aol));
|
||||
}
|
||||
} else if (btn.getId() == R.id.btnTwitter) {
|
||||
if (!getMAThemeString().equals("dark")) {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_twitter_light));
|
||||
} else {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_twitter));
|
||||
}
|
||||
} else if (btn.getId() == R.id.btnLive) {
|
||||
if (!getMAThemeString().equals("dark")) {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_live_light));
|
||||
} else {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_live));
|
||||
}
|
||||
} else if (btn.getId() == R.id.btnOpenID) {
|
||||
if (!getMAThemeString().equals("dark")) {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_openid_light));
|
||||
} else {
|
||||
btn.setImageDrawable(getResources().getDrawable(
|
||||
R.drawable.logo_openid));
|
||||
}
|
||||
}
|
||||
|
||||
btn.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ImageButton img = (ImageButton) v;
|
||||
Intent intent = new Intent(getApplicationContext(),
|
||||
MediNETActivity.class);
|
||||
|
||||
if (img.getId() == R.id.btnGoogle) {
|
||||
intent.putExtra("provider", "Google");
|
||||
} else if (img.getId() == R.id.btnFacebook) {
|
||||
intent.putExtra("provider", "Facebook");
|
||||
} else if (img.getId() == R.id.btnAOL) {
|
||||
intent.putExtra("provider", "AOL");
|
||||
} else if (img.getId() == R.id.btnTwitter) {
|
||||
intent.putExtra("provider", "Twitter");
|
||||
} else if (img.getId() == R.id.btnLive) {
|
||||
intent.putExtra("provider", "Live");
|
||||
} else if (img.getId() == R.id.btnOpenID) {
|
||||
intent.putExtra("provider", "OpenID");
|
||||
}
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
if (alertDialog != null) {
|
||||
try {
|
||||
alertDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
alertDialog = new AlertDialog.Builder(activity)
|
||||
.setView(view)
|
||||
.setTitle(R.string.signInToMediNET)
|
||||
.setIcon(
|
||||
activity.getResources().getDrawable(
|
||||
getTheme().obtainStyledAttributes(getMATheme(true),
|
||||
new int[]{R.attr.actionIconForward})
|
||||
.getResourceId(0, 0)
|
||||
)
|
||||
).create();
|
||||
alertDialog
|
||||
.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
if (getMediNETKey() == "") {
|
||||
getMediNET().status = "disconnected";
|
||||
getMediNET().updated();
|
||||
}
|
||||
}
|
||||
});
|
||||
alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
if (getMediNETKey() == "") {
|
||||
getMediNET().status = "disconnected";
|
||||
getMediNET().updated();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
alertDialog.show();
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
public AlertDialog showStaleDataDialog() {
|
||||
Log.d("MeditationAssistant", "Showing stale data dialog");
|
||||
|
||||
|
@ -1339,31 +1177,4 @@ public class MeditationAssistant extends Application {
|
|||
GLOBAL_TRACKER, // Tracker used by all the apps from a company. eg: roll-up tracking.
|
||||
ECOMMERCE_TRACKER, // Tracker used by all ecommerce transactions from a company.
|
||||
}
|
||||
|
||||
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
|
||||
@Override
|
||||
public void run(AccountManagerFuture<Bundle> result) {
|
||||
|
||||
Intent launch = null;
|
||||
try {
|
||||
launch = (Intent) result.getResult().get(AccountManager.KEY_INTENT);
|
||||
|
||||
if (launch == null) {
|
||||
String authtoken = result.getResult().getString(AccountManager.KEY_AUTHTOKEN);
|
||||
if (!authtoken.equals("")) {
|
||||
getMediNET().signInWithAuthToken(authtoken);
|
||||
}
|
||||
}
|
||||
} catch (OperationCanceledException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (AuthenticatorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (launch != null) {
|
||||
signin_activity.startActivityForResult(launch, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -331,8 +331,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private static boolean isSimplePreferences(Context context) {
|
||||
return Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
|
||||
|| !isXLargeTablet(context);
|
||||
return !isXLargeTablet(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -497,9 +496,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||
public boolean onPreferenceClick(Preference arg0) {
|
||||
|
||||
if (getMeditationAssistant().getMediNETKey().equals("")) {
|
||||
getMeditationAssistant().getMediNET().askToSignIn();
|
||||
getMeditationAssistant().shortToast(
|
||||
getString(R.string.signInToMediNET));
|
||||
getMeditationAssistant().startAuth(true);
|
||||
} else {
|
||||
ArrayList<SessionSQL> sessionssql = getMeditationAssistant().db.getAllLocalSessions();
|
||||
|
||||
|
@ -529,9 +526,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||
@Override
|
||||
public boolean onPreferenceClick(Preference arg0) {
|
||||
if (getMeditationAssistant().getMediNETKey().equals("")) {
|
||||
getMeditationAssistant().getMediNET().askToSignIn();
|
||||
getMeditationAssistant().shortToast(
|
||||
getString(R.string.signInToImport));
|
||||
getMeditationAssistant().startAuth(true);
|
||||
} else {
|
||||
if (getMeditationAssistant().getTimestamp()
|
||||
- importsessions_lastlick > 5) {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/browser_icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:contentDescription="@string/browser"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/browser_label"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"/>
|
||||
|
||||
</LinearLayout>
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 9.2 KiB |
|
@ -21,10 +21,11 @@
|
|||
<string name="announcement">Ankündigung</string>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="permissionRequest">Berechtigungsanfrage</string>
|
||||
<string name="permissionRequestAccounts">Die Berechtigung auf Ihre Google Account zugreifen zu dürfen ist als "Kontake" beachrieben. Ihre Kontake western nicht gelesen. Wenn Sie diesel Berechtigung akzeptieren müssen Sie um sich bei MediNET anzumelden Ihre Google Accountdaten nicht immer eingeben.</string>
|
||||
<string name="permissionRequestReadExternal">Diesel Berechtigung wird benötigt um einen beliebigen Ton von Ihrem Great auszuwählen. </string>
|
||||
<string name="permissionRequestNotificationControl">Bitte gewähren Sie auf dem nächsten Bildschirm Zugriff um die Funktion \'Nicht stören\' kontrollieren zu können.</string>
|
||||
<string name="deny">Verweigern </string>
|
||||
<string name="tryAgain">Erneut versuchen</string>
|
||||
|
||||
<!-- Main Activity -->
|
||||
|
@ -104,7 +105,7 @@
|
|||
<!-- Progress -->
|
||||
<string name="calendar">Kalender</string>
|
||||
<string name="statistics">Statistiken</string>
|
||||
<string name="totalTimeSpentMeditating">Gesamte beim Meditieren verbrachte Zeit</string>
|
||||
<string name="totalTimeSpentMeditating">Meditationsdauer ingesamt</string>
|
||||
<string name="dayMondayShort">Mo</string>
|
||||
<string name="dayTuesdayShort">Di</string>
|
||||
<string name="dayWednesdayShort">Mi</string>
|
||||
|
@ -203,6 +204,8 @@
|
|||
<string name="extralarge">Riesig</string>
|
||||
<string name="restartApp">Anwendung neustarten, um neue Einstellungen anzuwenden</string>
|
||||
<string name="pref_notificationcontrol">Klingelton und Benachrichtigungen</string>
|
||||
<string name="pref_notificationcontrol_priority">Priorität</string>
|
||||
<string name="pref_notificationcontrol_alarms">Nur Alarme</string>
|
||||
<string name="pref_notificationcontrol_vibrate">Einstellen auf Vibration</string>
|
||||
<string name="pref_notificationcontrol_silent">Stummschalten</string>
|
||||
<string name="pref_daily_reminder">Tägliche Erinnerung</string>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<string name="about">Acerca</string>
|
||||
<string name="yes">Si</string>
|
||||
<string name="no">No</string>
|
||||
|
||||
<string name="delete">Borrar</string>
|
||||
<string name="sessions">Sesiones</string>
|
||||
<string name="community">Comunidad</string>
|
||||
|
@ -19,10 +20,19 @@
|
|||
<string name="groups">Grupos</string>
|
||||
<string name="announcement">Anuncio</string>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Main Activity -->
|
||||
<string name="timer">Temporizador</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="set">Establecer</string>
|
||||
<string name="confirm">Confirmar</string>
|
||||
|
@ -32,48 +42,70 @@
|
|||
<string name="end">Ende</string>
|
||||
<string name="pauseOrEnd">Pausa o ende</string>
|
||||
<string name="resumeOrEnd">Sesión pausada, mantener para terminar</string>
|
||||
|
||||
|
||||
<string name="mediNETConnecting">Conectando...</string>
|
||||
<string name="mediNETConnected">Conectando a MediNET</string>
|
||||
<string name="sessionInProgress">Sesión en progreso</string>
|
||||
<string name="progress">Progreso</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="timed">Terminar %s</string>
|
||||
<string name="endAt">Terminar en</string>
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="presetLabelEndAt">Terminar %s</string>
|
||||
|
||||
<!-- About -->
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="version">Versión %s</string>
|
||||
<string name="translate">Traducir</string>
|
||||
|
||||
|
||||
|
||||
<string name="howToMeditate">Como meditar</string>
|
||||
<string name="share">Compartir</string>
|
||||
|
||||
<!--Short text displayed in sent application invitations [CHAR LIMIT=100] -->
|
||||
|
||||
|
||||
|
||||
<!-- Sessions -->
|
||||
<string name="session">Sesión</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Session complete -->
|
||||
|
||||
|
||||
<string name="sessionMessagePlaceholder">Mensaje</string>
|
||||
|
||||
|
||||
<string name="aMoment">a momento</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Sign In -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Progress -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="dayMondayShort">Lun</string>
|
||||
<string name="dayTuesdayShort">Mar</string>
|
||||
<string name="dayWednesdayShort">Mie</string>
|
||||
|
@ -82,23 +114,145 @@
|
|||
<string name="daySaturdayShort">Sab</string>
|
||||
<string name="daySundayShort">Dom</string>
|
||||
<string name="addSession">Añadir sesión</string>
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="started">Iniciado</string>
|
||||
<string name="completed">Completado</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Settings -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- MediNET -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<plurals name="numtimes">
|
||||
<item quantity="one">%s time</item>
|
||||
<item quantity="other">%s times</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="sessionsImported">
|
||||
<item quantity="one">%s sesión importado</item>
|
||||
<item quantity="other">%s sesiones importado</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="sessionsUploaded">
|
||||
<item quantity="one">Uploaded %s session</item>
|
||||
<item quantity="other">Uploaded %s sessions</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
|
||||
|
||||
<plurals name="daysOfMeditationMinimal">
|
||||
<item quantity="one">%d day</item>
|
||||
<item quantity="other">%d days</item>
|
||||
</plurals>
|
||||
<plurals name="daysOfMeditation">
|
||||
<item quantity="one">%d día de meditación</item>
|
||||
<item quantity="other">%d días de meditación</item>
|
||||
|
@ -108,6 +262,15 @@
|
|||
<item quantity="other">días de meditación</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Widgets -->
|
||||
<string name="widget1x1" tools:ignore="UnusedResources">Asistente de meditación 1x1</string>
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<string name="appName">Meditasjonsassistent Gratis</string>
|
||||
<string name="appNameShort">Meditasjonsassistent</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="no">Nei</string>
|
||||
<string name="openWith">Åpne med</string>
|
||||
<string name="delete">Slett</string>
|
||||
<string name="sessions">Økter</string>
|
||||
<string name="community">Fellesskap</string>
|
||||
<string name="forum">Forum</string>
|
||||
<string name="rate">Ranger</string>
|
||||
<string name="refresh">Oppdater</string>
|
||||
<string name="page">Side</string>
|
||||
<string name="back">Tilbake</string>
|
||||
<string name="forward">Fremover</string>
|
||||
<string name="account">Konto</string>
|
||||
<string name="groups">Grupper</string>
|
||||
<string name="announcement">Kunngjøringer</string>
|
||||
|
||||
<!-- Permissions -->
|
||||
<string name="permissionRequest">Forespørsel om tillatelse</string>
|
||||
<string name="permissionRequestAccounts">Tillatelsen som gir tilgang til Google-kontoen din kalles "Kontakter". Kontaktene dine vil ikke bli lest.\n\nHvis du gir denne tilgangen slipper du å skrive inn brukernavnet og passordet til Google-kontoen din når du logger på MediNET</string>
|
||||
<string name="permissionRequestReadExternal">Tillatelsen trengs for å kunne velge andre lydfiler fra enheten.</string>
|
||||
<string name="permissionRequestNotificationControl">Vennligst gi tillatelse i neste steg for å kunne kontrollere "Ikke forstyrr"</string>
|
||||
<string name="deny">Nekt</string>
|
||||
<string name="tryAgain">Prøv igjen</string>
|
||||
|
||||
<!-- Main Activity -->
|
||||
<string name="timer">Tidtaker</string>
|
||||
<string name="timerHelp">Akkurat nå er tidtakeren stilt inn på 15 minutter. Du kan endre varigheten, sette den til å stoppe på et visst klokkeslett eller slå av alarmen helt. Trykk på tidtakeren nå for å se disse mulighetene.</string>
|
||||
<string name="settingsHelp">Denne applikasjonen tilbyr mange funksjoner og tilpasningsmuligheter, blant annet å sette enheten i stillemodus automatisk og å gi deg daglig påminnelse om å meditere. Trykk på innstillingsikonet nå for å se disse mulighetene.</string>
|
||||
<string name="medinetHelp">Logg på MediNET for å lagre øktene dine på nett. Hvis du gjør det kan du importere øktene dine igjen hvis de blir borte fra enheten din. Denne funksjonen er helt valgfri; å lagre øktene lokalt vil ikke gå ut over bruksopplevelsen.\n\nOg med det er denne introduksjonen over. Jeg håper at du får mye ut av Meditasjonsassistenten.</string>
|
||||
<string name="cancel">Avbryt</string>
|
||||
<string name="set">Sett</string>
|
||||
<string name="confirm">Bekreft</string>
|
||||
<string name="meditate">Mediter</string>
|
||||
<string name="tapToSkip">Hopp over</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="end">Avslutt</string>
|
||||
<string name="pauseOrEnd">Pause eller avslutt</string>
|
||||
<string name="resumeOrEnd">Gjenoppta eller avslutt</string>
|
||||
<string name="pausedNotification">Økt satt på pause, hold for å avslutte</string>
|
||||
<string name="mediNETConnecting">Kobler til...</string>
|
||||
<string name="mediNETConnected">Koble til MediNET</string>
|
||||
<string name="sessionInProgress">Økt pågår</string>
|
||||
<string name="progress">Fremgang</string>
|
||||
<string name="setPreset">Bruk forhåndsvalg</string>
|
||||
<string name="setPresetHint">Hold for å bruke forhåndsvalg</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- About -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--Short text displayed in sent application invitations [CHAR LIMIT=100] -->
|
||||
|
||||
|
||||
<!-- Sessions -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Session complete -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Sign In -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Progress -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Settings -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- MediNET -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Widgets -->
|
||||
|
||||
|
||||
|
||||
|
||||
</resources>
|
|
@ -97,6 +97,8 @@
|
|||
<string name="sessionDeletedLocally">Session deleted locally</string>
|
||||
|
||||
<!-- Sign In -->
|
||||
<string name="browser">Browser</string>
|
||||
<string name="useBrowser">Use browser:</string>
|
||||
<string name="signInWith">Sign in with…</string>
|
||||
<string name="signInWithProvider">Sign in with %s…</string>
|
||||
<string name="signInWithOpenID">OpenID - Facebook, Twitter, etc.</string>
|
||||
|
@ -248,7 +250,6 @@
|
|||
</plurals>
|
||||
|
||||
<string name="sessionsNotImported">Local data is up to date</string>
|
||||
<string name="signInToImport">Sign in to import session data</string>
|
||||
|
||||
<plurals name="daysOfMeditationMinimal">
|
||||
<item quantity="one">%d day</item>
|
||||
|
@ -268,7 +269,6 @@
|
|||
<string name="signOut">Sign out</string>
|
||||
<string name="signOutOfMediNET">Sign out of MediNET</string>
|
||||
<string name="signOutOfMediNETConfirmTitle">Sign out of MediNET?</string>
|
||||
<string name="signOutOfMediNETConfirm">You are signed in with %s.</string>
|
||||
<string name="rateMeditationAssistant">Rate Meditation Assistant</string>
|
||||
<string name="rateMeditationAssistantText">If you have found this application beneficial to your meditation practice, would you please add a rating?\n\nThe paid version of this app contains no ads and features home screen widgets. Please consider purchasing it if you are able to.\n\nThis dialog will not appear again.</string>
|
||||
<string name="translateMeditationAssistantText">Would you please help Meditation Assistant reach a wider audience by translating it into another language?\n\nTranslating is eaily done through an online interface. You can visit the translation webpage later by clicking Translate from the About window.\n\nThis dialog will not appear again.</string>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
/*
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.data.FreezableUtils;
|
||||
|
@ -50,6 +50,6 @@ public class WearListenerService extends WearableListenerService {
|
|||
// Send the RPC
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, nodeId,
|
||||
DATA_ITEM_RECEIVED_PATH, payload);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -1,36 +1,37 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
/*buildscript {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.1'
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion '24.0.1'
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.1'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 20
|
||||
targetSdkVersion 24
|
||||
targetSdkVersion 26
|
||||
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false /* Docs say to not compress wear APK */
|
||||
minifyEnabled false /* Docs say to not compress wear APK *//*
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:24.2.0'
|
||||
|
||||
compile 'com.google.android.support:wearable:1.1.0'
|
||||
compile 'com.google.android.gms:play-services-wearable:9.4.0'
|
||||
}
|
||||
compile 'com.google.android.gms:play-services-wearable:11.0.4'
|
||||
}*/
|
||||
|
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 13 KiB |
|
@ -10,6 +10,7 @@ Download
|
|||
[paid](https://play.google.com/store/apps/details?id=sh.ftp.rocketninelabs.meditationassistant.full)
|
||||
- Amazon: [free](http://www.amazon.com/Rocket-Nine-Laboratories-Meditation-Assistant/dp/B00BQVZ9DU) /
|
||||
[paid](http://www.amazon.com/Rocket-Nine-Laboratories-Meditation-Assistant/dp/B00BQVXDL0/)
|
||||
- F-Droid: [free](https://f-droid.org/packages/sh.ftp.rocketninelabs.meditationassistant.opensource/)
|
||||
|
||||
|
||||
Remove Ads
|
||||
|
@ -19,7 +20,7 @@ Please purchase the paid version of the app to remove advertisements.
|
|||
|
||||
Donate
|
||||
------------
|
||||
[Click here to donate](https://medinet.ftp.sh/donate/) via PayPal.
|
||||
[Click here to donate](https://rocketnine.space/donate/) via PayPal.
|
||||
|
||||
|
||||
Get Support
|
||||
|
|
8
TODO
|
@ -19,3 +19,11 @@ Migrate all icons to vectors
|
|||
Merge 2x1 and 3x1 widgets into a single size-aware widget
|
||||
|
||||
Automatic session upload
|
||||
|
||||
Add warning for all MedINET connections <= version 5, as version 6 is used by all still-supported (Android 4.1+) devices
|
||||
|
||||
Allow OpenID signin using AppAuth
|
||||
|
||||
Update remaining logo icons to new logo, including notification icon, check on new material guides for new format
|
||||
|
||||
Set new default theme to use blue that matches logo, offer old theme still as "Holographic Dark"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#Tue Aug 23 13:49:49 PDT 2016
|
||||
#Sat Sep 16 15:53:03 PDT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
include ':MeditationAssistant', ':MeditationAssistantWear'
|
||||
include ':MeditationAssistant'
|
||||
// TODO: Add when wear app is ready
|
||||
// , ':MeditationAssistantWear'
|
||||
|
|