mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-10 22:34:15 +01:00
Implement biometric support
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
ab75a89e30
commit
f7151d8f15
@ -21,24 +21,18 @@
|
|||||||
package com.nextcloud.talk.activities;
|
package com.nextcloud.talk.activities;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.KeyguardManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.webkit.SslErrorHandler;
|
import android.webkit.SslErrorHandler;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.biometric.BiometricPrompt;
|
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.events.CertificateEvent;
|
import com.nextcloud.talk.events.CertificateEvent;
|
||||||
import com.nextcloud.talk.utils.HandlerExecutor;
|
|
||||||
import com.nextcloud.talk.utils.SecurityUtils;
|
import com.nextcloud.talk.utils.SecurityUtils;
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
|
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
|
||||||
@ -52,12 +46,10 @@ import java.security.cert.CertificateParsingException;
|
|||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public class BaseActivity extends AppCompatActivity {
|
public class BaseActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "BaseActivity";
|
private static final String TAG = "BaseActivity";
|
||||||
private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
EventBus eventBus;
|
EventBus eventBus;
|
||||||
@ -68,8 +60,6 @@ public class BaseActivity extends AppCompatActivity {
|
|||||||
@Inject
|
@Inject
|
||||||
Context context;
|
Context context;
|
||||||
|
|
||||||
private KeyguardManager keyguardManager;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
@ -89,64 +79,6 @@ public class BaseActivity extends AppCompatActivity {
|
|||||||
} else {
|
} else {
|
||||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
checkIfWeAreSecure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
|
||||||
private void checkIfWeAreSecure() {
|
|
||||||
keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
|
|
||||||
if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) {
|
|
||||||
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
|
||||||
if (SecurityUtils.isFingerprintAvailable(context)) {
|
|
||||||
showBiometricDialog();
|
|
||||||
} else {
|
|
||||||
showAuthenticationScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
|
||||||
private void showBiometricDialog() {
|
|
||||||
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
|
|
||||||
.setTitle(String.format(context.getString(R.string.nc_biometric_unlock), context.getString(R.string.nc_app_name)))
|
|
||||||
.setNegativeButtonText(context.getString(R.string.nc_cancel))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Executor mainExecutor = new HandlerExecutor(new Handler(getMainLooper()));
|
|
||||||
|
|
||||||
final BiometricPrompt biometricPrompt = new BiometricPrompt(this, mainExecutor,
|
|
||||||
new BiometricPrompt.AuthenticationCallback() {
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
biometricPrompt.authenticate(promptInfo, SecurityUtils.getCryptoObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showAuthenticationScreen() {
|
|
||||||
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
|
|
||||||
if (intent != null) {
|
|
||||||
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
|
||||||
// all went well
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we didnt auth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showCertificateDialog(X509Certificate cert, MagicTrustManager magicTrustManager,
|
public void showCertificateDialog(X509Certificate cert, MagicTrustManager magicTrustManager,
|
||||||
|
@ -20,9 +20,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.nextcloud.talk.activities;
|
package com.nextcloud.talk.activities;
|
||||||
|
|
||||||
|
import android.app.KeyguardManager;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
@ -31,13 +35,12 @@ import com.bluelinelabs.conductor.Conductor;
|
|||||||
import com.bluelinelabs.conductor.Router;
|
import com.bluelinelabs.conductor.Router;
|
||||||
import com.bluelinelabs.conductor.RouterTransaction;
|
import com.bluelinelabs.conductor.RouterTransaction;
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||||
|
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.controllers.CallNotificationController;
|
import com.nextcloud.talk.controllers.*;
|
||||||
import com.nextcloud.talk.controllers.ChatController;
|
|
||||||
import com.nextcloud.talk.controllers.ConversationsListController;
|
|
||||||
import com.nextcloud.talk.controllers.ServerSelectionController;
|
|
||||||
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
|
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
|
||||||
|
import com.nextcloud.talk.utils.SecurityUtils;
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
@ -48,7 +51,6 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public final class MainActivity extends BaseActivity implements ActionBarProvider {
|
public final class MainActivity extends BaseActivity implements ActionBarProvider {
|
||||||
|
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
|
|
||||||
@BindView(R.id.toolbar)
|
@BindView(R.id.toolbar)
|
||||||
@ -113,6 +115,30 @@ public final class MainActivity extends BaseActivity implements ActionBarProvide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
checkIfWeAreSecure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
public void checkIfWeAreSecure() {
|
||||||
|
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
|
||||||
|
if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) {
|
||||||
|
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
||||||
|
if (router != null && router.getControllerWithTag(LockedController.TAG) == null) {
|
||||||
|
router.pushController(RouterTransaction.with(new LockedController())
|
||||||
|
.pushChangeHandler(new VerticalChangeHandler())
|
||||||
|
.popChangeHandler(new VerticalChangeHandler())
|
||||||
|
.tag(LockedController.TAG));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent) {
|
protected void onNewIntent(Intent intent) {
|
||||||
@ -133,6 +159,10 @@ public final class MainActivity extends BaseActivity implements ActionBarProvide
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
|
if (router.getControllerWithTag(LockedController.TAG) != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!router.handleBack()) {
|
if (!router.handleBack()) {
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,6 @@ public class AccountVerificationController extends BaseController {
|
|||||||
} else {
|
} else {
|
||||||
checkEverything();
|
checkEverything();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkEverything() {
|
private void checkEverything() {
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.controllers;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.KeyguardManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.biometric.BiometricPrompt;
|
||||||
|
import autodagger.AutoInjector;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
import com.nextcloud.talk.R;
|
||||||
|
import com.nextcloud.talk.activities.MainActivity;
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.controllers.base.BaseController;
|
||||||
|
import com.nextcloud.talk.utils.SecurityUtils;
|
||||||
|
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
|
public class LockedController extends BaseController {
|
||||||
|
public static final String TAG = "LockedController";
|
||||||
|
private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AppPreferences appPreferences;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||||
|
return inflater.inflate(R.layout.controller_locked, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
@Override
|
||||||
|
protected void onViewBound(@NonNull View view) {
|
||||||
|
super.onViewBound(view);
|
||||||
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
|
if (getActionBar() != null) {
|
||||||
|
getActionBar().hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
showBiometricDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
@OnClick(R.id.unlockTextView)
|
||||||
|
void unlock() {
|
||||||
|
checkIfWeAreSecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
private void showBiometricDialog() {
|
||||||
|
Context context = getActivity();
|
||||||
|
|
||||||
|
if (context != null) {
|
||||||
|
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
|
||||||
|
.setTitle(String.format(context.getString(R.string.nc_biometric_unlock), context.getString(R.string.nc_app_name)))
|
||||||
|
.setNegativeButtonText(context.getString(R.string.nc_cancel))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Executor executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
|
final BiometricPrompt biometricPrompt = new BiometricPrompt((MainActivity) context, executor,
|
||||||
|
new BiometricPrompt.AuthenticationCallback() {
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||||
|
super.onAuthenticationSucceeded(result);
|
||||||
|
Log.d(TAG, "Fingerprint recognised successfully");
|
||||||
|
getRouter().popCurrentController();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationFailed() {
|
||||||
|
super.onAuthenticationFailed();
|
||||||
|
Log.d(TAG, "Fingerprint not recognised");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
|
||||||
|
super.onAuthenticationError(errorCode, errString);
|
||||||
|
showAuthenticationScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
biometricPrompt.authenticate(promptInfo, SecurityUtils.getCryptoObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
private void checkIfWeAreSecure() {
|
||||||
|
if (getActivity() != null) {
|
||||||
|
KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
|
||||||
|
if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) {
|
||||||
|
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
||||||
|
showBiometricDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showAuthenticationScreen() {
|
||||||
|
if (getActivity() != null) {
|
||||||
|
KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
|
||||||
|
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
|
||||||
|
if (intent != null) {
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS ) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
||||||
|
Log.d(TAG, "All went well, dismiss locked controller");
|
||||||
|
getRouter().popCurrentController();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Authorization failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* 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 com.nextcloud.talk.utils;
|
|
||||||
import android.os.Handler;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
|
||||||
/**
|
|
||||||
* An adapter {@link Executor} that posts all executed tasks onto the given
|
|
||||||
* {@link Handler}.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public class HandlerExecutor implements Executor {
|
|
||||||
private final Handler mHandler;
|
|
||||||
|
|
||||||
public HandlerExecutor(@NonNull Handler handler) {
|
|
||||||
mHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable command) {
|
|
||||||
if (!mHandler.post(command)) {
|
|
||||||
throw new RejectedExecutionException(mHandler + " is shutting down");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.utils;
|
package com.nextcloud.talk.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.security.keystore.KeyGenParameterSpec;
|
import android.security.keystore.KeyGenParameterSpec;
|
||||||
@ -30,7 +29,6 @@ import android.security.keystore.UserNotAuthenticatedException;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.biometric.BiometricPrompt;
|
import androidx.biometric.BiometricPrompt;
|
||||||
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
|
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
|
||||||
@ -130,9 +128,4 @@ public class SecurityUtils {
|
|||||||
int indexOfValidity = entryValues.indexOf(validity);
|
int indexOfValidity = entryValues.indexOf(validity);
|
||||||
return entryIntValues[indexOfValidity];
|
return entryIntValues[indexOfValidity];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFingerprintAvailable(Context context) {
|
|
||||||
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.from(context);
|
|
||||||
return fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
53
app/src/main/res/layout/controller_locked.xml
Normal file
53
app/src/main/res/layout/controller_locked.xml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/ic_launcher_background"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/appLogo"
|
||||||
|
android:layout_width="92dp"
|
||||||
|
android:layout_height="92dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_launcher_foreground" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignTop="@id/appLogo"
|
||||||
|
android:layout_alignEnd="@id/appLogo"
|
||||||
|
android:src="@drawable/ic_lock_white_24px" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/appLogo"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="@dimen/margin_between_elements"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:id="@+id/unlockTextView"
|
||||||
|
android:text="@string/nc_locked"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
</RelativeLayout>
|
@ -102,6 +102,7 @@
|
|||||||
<string name="nc_settings_link_previews_title">Show link previews</string>
|
<string name="nc_settings_link_previews_title">Show link previews</string>
|
||||||
<string name="nc_settings_link_previews_desc">Allows previews of content from received links for supported services</string>
|
<string name="nc_settings_link_previews_desc">Allows previews of content from received links for supported services</string>
|
||||||
<string name="nc_settings_link_previews_key" translatable="false">link_previews</string>
|
<string name="nc_settings_link_previews_key" translatable="false">link_previews</string>
|
||||||
|
<string name="nc_locked">Tap to unlock</string>
|
||||||
|
|
||||||
<string name="nc_screen_lock_timeout_30">30 seconds</string>
|
<string name="nc_screen_lock_timeout_30">30 seconds</string>
|
||||||
<string name="nc_screen_lock_timeout_60">1 minute</string>
|
<string name="nc_screen_lock_timeout_60">1 minute</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user