Commit dddf7885 authored by Thomas Markiewicz's avatar Thomas Markiewicz

Merged upstream v0.9.9

parents e1831a93 5da259a7
......@@ -9,10 +9,10 @@ steps:
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build is long
queue: "medium"
queue: "xlarge"
commands:
- "./set_debug_env.sh"
- "./gradlew clean lintAppRelease assembleAppDebug --stacktrace"
- "./gradlew --no-daemon clean lintAppRelease assembleAppDebug --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/app/debug/*.apk"
branches: "develop feature/*"
......@@ -24,10 +24,10 @@ steps:
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build is long
queue: "medium"
queue: "xlarge"
commands:
- "./set_debug_env.sh"
- "./gradlew clean lintAppfdroidRelease assembleAppfdroidDebug --stacktrace"
- "./gradlew --no-daemon clean lintAppfdroidRelease assembleAppfdroidDebug --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/appfdroid/debug/*.apk"
branches: "develop feature/*"
......@@ -39,9 +39,9 @@ steps:
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build is long
queue: "medium"
queue: "xlarge"
commands:
- "./gradlew clean assembleAppRelease --stacktrace"
- "./gradlew --no-daemon clean assembleAppRelease --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/app/release/*.apk"
branches: "master"
......@@ -52,4 +52,5 @@ steps:
# Code quality
- label: "Code quality"
command: "./tools/check/check_code_quality.sh"
commands:
- "./tools/check/check_code_quality.sh"
\ No newline at end of file
......@@ -28,7 +28,7 @@ ext {
// during development the versionName ends with -SNAPSHOT. As the code stabilizes and release nears
// one or many Release Candidates are tagged. These all end with "-RC1", "-RC2" etc.
// And the final release is without any suffix.
versionNameProp = "1.0.3"
versionNameProp = "1.0.4"
// versionCode rules:
// (major * 1000000) + (minor * 10000) + (patch * 100) + candidate;
......@@ -36,7 +36,7 @@ ext {
// 00 for -SNAPSHOT
// 01..98 for RC
// 99 for final release
versionCodeProp = 1000399
versionCodeProp = 1000401
buildNumberProp = System.getenv("CI_PIPELINE_IID") as String ?: "0"
}
......
......@@ -16,7 +16,7 @@ version=1.0.0
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
# org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
......
......@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
......@@ -106,6 +106,7 @@ android {
buildTypes {
debug {
resValue "bool", "debug_mode", "true"
resValue "string", "git_revision", "\"${gitRevision()}\""
resValue "string", "git_revision_date", "\"${gitRevisionDate()}\""
......@@ -235,6 +236,7 @@ dependencies {
// Epoxy
implementation 'com.airbnb.android:epoxy:3.7.0'
implementation 'com.airbnb.android:mvrx:1.0.1'
kapt 'com.airbnb.android:epoxy-processor:3.7.0'
// Network
......@@ -263,7 +265,7 @@ dependencies {
/************* Matrix SDK management **************/
// update settings.gradle
// use the matrix SDK as external dependency
implementation 'com.github.matrix-org:matrix-android-sdk:v0.9.27'
implementation 'com.github.matrix-org:matrix-android-sdk:v0.9.32'
// use the matrix SDK as a sub project
// you have to uncomment some lines in settings.gradle
//implementation project(':matrix-sdk')
......@@ -277,7 +279,7 @@ dependencies {
/************* flavors management **************/
// app flavor only
appImplementation('com.google.firebase:firebase-messaging:17.4.0') {
appImplementation('com.google.firebase:firebase-messaging:20.0.0') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
......
......@@ -59,11 +59,8 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
*
* @param message the message
*/
override fun onMessageReceived(message: RemoteMessage?) {
if (message == null || message.data == null) {
Log.e(LOG_TAG, "## onMessageReceived() : received a null message or message with no data")
return
}
override fun onMessageReceived(message: RemoteMessage) {
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
Log.i(LOG_TAG, "## onMessageReceived()" + message.data.toString())
Log.i(LOG_TAG, "## onMessageReceived() from FCM with priority " + message.priority)
......@@ -86,7 +83,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
* when the InstanceID token is initially generated, so this is where
* you retrieve the token.
*/
override fun onNewToken(refreshedToken: String?) {
override fun onNewToken(refreshedToken: String) {
Log.i(LOG_TAG, "onNewToken: FCM Token has been updated")
FcmHelper.storeFcmToken(this, refreshedToken)
Matrix.getInstance(this)?.pushManager?.resetFCMRegistration(refreshedToken)
......
......@@ -14,25 +14,22 @@
* limitations under the License.
*/
package im.vector.receiver;
package im.vector.receiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import im.vector.services.EventStreamServiceX
import org.matrix.androidsdk.core.Log
import org.matrix.androidsdk.core.Log;
class OnApplicationUpgradeReceiver : BroadcastReceiver() {
import im.vector.services.EventStreamServiceX;
public class OnApplicationUpgradeReceiver extends BroadcastReceiver {
private static final String LOG_TAG = OnApplicationUpgradeReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "## onReceive() : Application has been upgraded, restart event stream service.");
override fun onReceive(context: Context, intent: Intent) {
Log.d(LOG_TAG, "## onReceive() : Application has been upgraded, restart event stream service.")
EventStreamServiceX.onApplicationUpgrade(context)
}
// Start Event stream
EventStreamServiceX.Companion.onApplicationUpgrade(context);
companion object {
private val LOG_TAG = OnApplicationUpgradeReceiver::class.java.simpleName
}
}
......@@ -340,22 +340,22 @@
android:theme="@style/GroupAppTheme.Light"
android:windowSoftInputMode="adjustResize" />
<activity android:name=".activity.VectorUniversalLinkActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="vector.im" />
<data android:pathPrefix="/app/" />
<data android:pathPrefix="/beta/" />
<data android:pathPrefix="/develop/" />
<data android:pathPrefix="/staging/" />
<!-- mail validation -->
<data android:pathPrefix="/_matrix/" />
</intent-filter>
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.VIEW" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <category android:name="android.intent.category.BROWSABLE" />-->
<!-- <data android:scheme="http" />-->
<!-- <data android:scheme="https" />-->
<!-- <data android:host="vector.im" />-->
<!-- <data android:pathPrefix="/app/" />-->
<!-- <data android:pathPrefix="/beta/" />-->
<!-- <data android:pathPrefix="/develop/" />-->
<!-- <data android:pathPrefix="/staging/" />-->
<!-- &lt;!&ndash; mail validation &ndash;&gt;-->
<!-- <data android:pathPrefix="/_matrix/" />-->
<!-- </intent-filter>-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
......
......@@ -214,19 +214,23 @@ public class LoginHandler {
final String aClientSecret,
final String aSid,
final ApiCallback<Boolean> aRespCallback) {
final ThreePid pid = new ThreePid(null, ThreePid.MEDIUM_EMAIL);
ThirdPidRestClient restClient = new ThirdPidRestClient(aHomeServerConfig);
pid.submitValidationToken(restClient, aToken, aClientSecret, aSid, new UnrecognizedCertApiCallback<Boolean>(aHomeServerConfig, aRespCallback) {
@Override
public void onSuccess(Boolean info) {
aRespCallback.onSuccess(info);
}
@Override
public void onAcceptedCert() {
submitEmailTokenValidation(aCtx, aHomeServerConfig, aToken, aClientSecret, aSid, aRespCallback);
}
});
restClient.submitValidationToken(
ThreePid.MEDIUM_EMAIL,
aToken,
aClientSecret,
aSid,
new UnrecognizedCertApiCallback<Boolean>(aHomeServerConfig, aRespCallback) {
@Override
public void onSuccess(Boolean info) {
aRespCallback.onSuccess(info);
}
@Override
public void onAcceptedCert() {
submitEmailTokenValidation(aCtx, aHomeServerConfig, aToken, aClientSecret, aSid, aRespCallback);
}
});
}
}
......@@ -117,6 +117,8 @@ public class Matrix {
@Nullable
private KeyRequestHandler mKeyRequestHandler;
private Map<String, WidgetManagerProvider> mWidgetManagerProviders = new HashMap<>();
// i.e the event has been read from another client
private static final MXEventListener mLiveEventListener = new MXEventListener() {
boolean mClearCacheRequired = false;
......@@ -133,10 +135,12 @@ public class Matrix {
public void onLiveEvent(Event event, RoomState roomState) {
mRefreshUnreadCounter |= Event.EVENT_TYPE_MESSAGE.equals(event.getType()) || Event.EVENT_TYPE_RECEIPT.equals(event.getType());
// TODO update to manage multisessions
WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(VectorApp.getInstance().getApplicationContext());
if (wm != null) {
wm.onLiveEvent(instance.getDefaultSession(), event);
WidgetManagerProvider wp = instance.mWidgetManagerProviders.get(instance.getDefaultSession().getMyUserId());
if (wp != null) {
WidgetsManager wm = wp.getWidgetManager(VectorApp.getInstance().getApplicationContext());
if (wm != null) {
wm.onLiveEvent(instance.getDefaultSession(), event);
}
}
}
......@@ -306,6 +310,23 @@ public class Matrix {
return sessions;
}
@Nullable
public WidgetManagerProvider getWidgetManagerProvider(MXSession session) {
if (session == null) {
return null;
}
return mWidgetManagerProviders.get(session.getMyUserId());
}
@Nullable
public static WidgetsManager getWidgetManager(Context activity) {
if (Matrix.getInstance(activity) == null) return null;
MXSession session = Matrix.getInstance(activity).getDefaultSession();
if (session == null) return null;
WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(activity).getWidgetManagerProvider(session);
if (widgetManagerProvider == null) return null;
return widgetManagerProvider.getWidgetManager(activity);
}
/**
* Retrieve the default session if one exists.
* <p>
......@@ -648,7 +669,9 @@ public class Matrix {
* @return The session.
*/
public MXSession createSession(HomeServerConnectionConfig hsConfig) {
return createSession(mAppContext, hsConfig);
MXSession session = createSession(mAppContext, hsConfig);
mWidgetManagerProviders.put(session.getMyUserId(), new WidgetManagerProvider(session));
return session;
}
/**
......
......@@ -41,6 +41,7 @@ import androidx.multidex.MultiDexApplication;
import com.facebook.stetho.Stetho;
import org.matrix.androidsdk.MXSession;
import org.matrix.androidsdk.call.MXCallsManager;
import org.matrix.androidsdk.core.Log;
import java.io.File;
......@@ -188,11 +189,6 @@ public class VectorApp extends MultiDexApplication {
Log.d(LOG_TAG, "onCreate");
super.onCreate();
PreferencesManager.setIntegrationManagerUrls(this,
getString(R.string.integrations_ui_url),
getString(R.string.integrations_rest_url),
getString(R.string.integrations_jitsi_widget_url));
mLifeCycleListener = new VectorLifeCycleObserver();
ProcessLifecycleOwner.get().getLifecycle().addObserver(mLifeCycleListener);
......@@ -214,6 +210,12 @@ public class VectorApp extends MultiDexApplication {
mActivityTransitionTimer = null;
mActivityTransitionTimerTask = null;
if (PreferencesManager.useDefaultTurnServer(this)) {
MXCallsManager.defaultStunServerUri = getString(R.string.default_stun_server);
} else {
MXCallsManager.defaultStunServerUri = null;
}
VECTOR_VERSION_STRING = Matrix.getInstance(this).getVersion(true, true);
// not the first launch
if (null != Matrix.getInstance(this).getDefaultSession()) {
......@@ -398,8 +400,6 @@ public class VectorApp extends MultiDexApplication {
for (MXSession session : sessions) {
if (session.isAlive()) {
session.setIsOnline(false);
session.setSyncDelay(pushManager.isBackgroundSyncAllowed() ? pushManager.getBackgroundSyncDelay() : 0);
session.setSyncTimeout(pushManager.getBackgroundSyncTimeOut());
// remove older medias
if ((System.currentTimeMillis() - mLastMediasCheck) < (24 * 60 * 60 * 1000)) {
......@@ -516,8 +516,6 @@ public class VectorApp extends MultiDexApplication {
for (MXSession session : sessions) {
session.getMyUser().refreshUserInfos(null);
session.setIsOnline(true);
session.setSyncDelay(0);
session.setSyncTimeout(0);
addSyncingSession(session);
}
......@@ -820,7 +818,6 @@ public class VectorApp extends MultiDexApplication {
return context;
}
/**
* The application is paused.
*/
......
......@@ -31,11 +31,11 @@ import im.vector.Matrix
import im.vector.R
import im.vector.activity.util.INTEGRATION_MANAGER_ACTIVITY_REQUEST_CODE
import im.vector.activity.util.TERMS_REQUEST_CODE
import im.vector.fragments.roomwidgets.WebviewPermissionUtils
import im.vector.types.JsonDict
import im.vector.types.WidgetEventData
import im.vector.util.AssetReader
import im.vector.util.toJsonMap
import im.vector.widgets.WidgetManagerProvider
import im.vector.widgets.WidgetsManager
import org.jetbrains.anko.toast
import org.matrix.androidsdk.MXSession
......@@ -88,7 +88,8 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() {
@CallSuper
override fun initUiAndData() {
mSession = Matrix.getInstance(this).getSession(intent.getStringExtra(EXTRA_MATRIX_ID))
val matrix = Matrix.getInstance(this)
mSession = matrix.getSession(intent.getStringExtra(EXTRA_MATRIX_ID))
if (null == mSession || !mSession!!.isAlive) {
Log.e(LOG_TAG, "## onCreate() : invalid session")
......@@ -100,7 +101,7 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() {
mRoom = mSession!!.dataHandler.getRoom(intent.getStringExtra(EXTRA_ROOM_ID))
widgetManager = WidgetManagerProvider.getWidgetManager(this) ?: run {
widgetManager = matrix.getWidgetManagerProvider(mSession)?.getWidgetManager(this) ?: run {
finish()
return
}
......@@ -148,8 +149,8 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() {
}
}
private fun presentTermsForServices(token: String?) {
val wm = WidgetManagerProvider.getWidgetManager(this)
private fun presentTermsForServices(token: String) {
val wm = Matrix.getInstance(this).getWidgetManagerProvider(mSession)?.getWidgetManager(this)//WidgetManagerProvider.getWidgetManagerProvider(this)
if (wm == null) { // should not happen
finish()
return
......@@ -194,7 +195,7 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() {
// Permission requests
it.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
runOnUiThread { request.grant(request.resources) }
WebviewPermissionUtils.promptForPermissions(R.string.room_widget_resource_permission_title, request, this@AbstractWidgetActivity)
}
override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
......
......@@ -316,39 +316,34 @@ public class CommonActivityUtils {
private static boolean isRecoveringFromInvalidatedToken = false;
public static void recoverInvalidatedToken() {
Log.e(LOG_TAG, "## recoverInvalidatedToken: Start Recover ");
if (isRecoveringFromInvalidatedToken) {
//ignore, we are doing it
Log.e(LOG_TAG, "## recoverInvalidatedToken: ignore, we are doing it");
return;
}
isRecoveringFromInvalidatedToken = true;
Context context = VectorApp.getCurrentActivity() != null ? VectorApp.getCurrentActivity() : VectorApp.getInstance();
try {
// Clear the credentials
Matrix.getInstance(context).getLoginStorage().clear() ;
VectorApp.getInstance().getNotificationDrawerManager().clearAllEvents();
EventStreamServiceX.Companion.onLogout(context);
// stopEventStream(context);
EventStreamServiceX.Companion.onApplicationStopped(context);
BadgeProxy.INSTANCE.updateBadgeCount(context, 0);
MXSession session = Matrix.getInstance(context).getDefaultSession();
// Publish to the server that we're now offline
MyPresenceManager.getInstance(context, session).advertiseOffline();
MyPresenceManager.remove(session);
// clear the preferences
PreferencesManager.clearPreferences(context);
// reset the FCM
Matrix.getInstance(context).getPushManager().resetFCMRegistration();
// clear the preferences
Matrix.getInstance(context).getPushManager().clearPreferences();
// Clear the credentials
Matrix.getInstance(context).getLoginStorage().clear();
// clear the tmp store list
Matrix.getInstance(context).clearTmpStoresList();
......@@ -358,20 +353,11 @@ public class CommonActivityUtils {
MXMediaCache.clearThumbnailsCache(context);
Matrix.getInstance(context).clearSessions(context, true, new SimpleApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
}
});
session.clear(context);
} catch (Exception e) {
Log.e(LOG_TAG, "## recoverInvalidatedToken: Error while cleaning: ", e);
} finally {
// go to login page
CommonActivityUtils.restartApp(context, true);
isRecoveringFromInvalidatedToken = false;
CommonActivityUtils.restartApp(context, true);
}
}
......@@ -436,15 +422,12 @@ public class CommonActivityUtils {
if (goToLoginPage) {
Activity activeActivity = VectorApp.getCurrentActivity();
final Context activeContext = (null == activeActivity) ? VectorApp.getInstance().getApplicationContext() : activeActivity;
// go to login page
Intent intent = new Intent(activeActivity, LoginActivity.class);
Intent intent = new Intent(activeContext, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
if (null != activeActivity) {
activeActivity.startActivity(intent);
} else {
context.startActivity(intent);
}
activeContext.startActivity(intent);
}
}
});
......
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.activity
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import im.vector.R
import im.vector.extensions.showPassword
object DialogUtils {
fun promptPassword(context: Context, errorText: String? = null, defaultPwd: String? = null,
done: (String) -> Unit,
cancel: (() -> Unit)? = null) {
val view: ViewGroup = LayoutInflater.from(context).inflate(R.layout.dialog_confirm_password, null) as ViewGroup
val showPassword: ImageView = view.findViewById(R.id.confirm_password_show_passwords)
val passwordTil: TextInputLayout = view.findViewById(R.id.confirm_password_til)
val passwordText: TextInputEditText = view.findViewById(R.id.password_label)
passwordText.setText(defaultPwd)
var passwordShown = false
showPassword.setOnClickListener {
passwordShown = !passwordShown
passwordText.showPassword(passwordShown)
showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
}
passwordTil.error = errorText
AlertDialog.Builder(context)
.setView(view)
.setPositiveButton(R.string._continue) { tv, _ ->
done(passwordText.text.toString())
}
.apply {
if (cancel != null) {
setNegativeButton(R.string.cancel) { _, _ ->
cancel()
}
}
}
.show()
}
}
\ No newline at end of file
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.activity
/**
* A fragment should implement this interface if it wants to intercept backPressed events.
* Any activity extending VectorAppCompatActivity will propagate back pressed event to child
* fragment that implements it.
*/
interface HandleBackParticipant {
/**
* Returns true, if the on back pressed event has been handled by this Fragment.
* Otherwise return false
*/
fun onBackPressed(): Boolean