mirror of
https://github.com/nextcloud/android.git
synced 2024-12-04 19:16:36 +01:00
Add support for QR codes & deep links
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
24cff7db24
commit
d47c77ca5c
14 changed files with 1276 additions and 68 deletions
|
@ -234,6 +234,7 @@ dependencies {
|
|||
implementation 'com.afollestad:sectioned-recyclerview:0.5.0'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15'
|
||||
implementation 'com.github.tobiaskaminsky:qrcodescanner:0.1.2.2' // 'com.github.blikoon:QRCodeScanner:0.1.2'
|
||||
|
||||
implementation 'org.parceler:parceler-api:1.1.12'
|
||||
annotationProcessor 'org.parceler:parceler:1.1.12'
|
||||
|
|
247
drawable_resources/qrcode.svg
Normal file
247
drawable_resources/qrcode.svg
Normal file
|
@ -0,0 +1,247 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" baseProfile="full" width="232" height="232" viewBox="0 0 232 232" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<desc></desc>
|
||||
<rect width="232" height="232" fill="#ffffff" cx="0" cy="0" />
|
||||
<defs>
|
||||
<rect id="p" width="8" height="8" />
|
||||
</defs>
|
||||
<g fill="#000000">
|
||||
<use x="32" y="32" xlink:href="#p" />
|
||||
<use x="32" y="40" xlink:href="#p" />
|
||||
<use x="32" y="48" xlink:href="#p" />
|
||||
<use x="32" y="56" xlink:href="#p" />
|
||||
<use x="32" y="64" xlink:href="#p" />
|
||||
<use x="32" y="72" xlink:href="#p" />
|
||||
<use x="32" y="80" xlink:href="#p" />
|
||||
<use x="32" y="96" xlink:href="#p" />
|
||||
<use x="32" y="104" xlink:href="#p" />
|
||||
<use x="32" y="112" xlink:href="#p" />
|
||||
<use x="32" y="120" xlink:href="#p" />
|
||||
<use x="32" y="128" xlink:href="#p" />
|
||||
<use x="32" y="144" xlink:href="#p" />
|
||||
<use x="32" y="152" xlink:href="#p" />
|
||||
<use x="32" y="160" xlink:href="#p" />
|
||||
<use x="32" y="168" xlink:href="#p" />
|
||||
<use x="32" y="176" xlink:href="#p" />
|
||||
<use x="32" y="184" xlink:href="#p" />
|
||||
<use x="32" y="192" xlink:href="#p" />
|
||||
<use x="40" y="32" xlink:href="#p" />
|
||||
<use x="40" y="80" xlink:href="#p" />
|
||||
<use x="40" y="96" xlink:href="#p" />
|
||||
<use x="40" y="104" xlink:href="#p" />
|
||||
<use x="40" y="144" xlink:href="#p" />
|
||||
<use x="40" y="192" xlink:href="#p" />
|
||||
<use x="48" y="32" xlink:href="#p" />
|
||||
<use x="48" y="48" xlink:href="#p" />
|
||||
<use x="48" y="56" xlink:href="#p" />
|
||||
<use x="48" y="64" xlink:href="#p" />
|
||||
<use x="48" y="80" xlink:href="#p" />
|
||||
<use x="48" y="96" xlink:href="#p" />
|
||||
<use x="48" y="104" xlink:href="#p" />
|
||||
<use x="48" y="120" xlink:href="#p" />
|
||||
<use x="48" y="128" xlink:href="#p" />
|
||||
<use x="48" y="144" xlink:href="#p" />
|
||||
<use x="48" y="160" xlink:href="#p" />
|
||||
<use x="48" y="168" xlink:href="#p" />
|
||||
<use x="48" y="176" xlink:href="#p" />
|
||||
<use x="48" y="192" xlink:href="#p" />
|
||||
<use x="56" y="32" xlink:href="#p" />
|
||||
<use x="56" y="48" xlink:href="#p" />
|
||||
<use x="56" y="56" xlink:href="#p" />
|
||||
<use x="56" y="64" xlink:href="#p" />
|
||||
<use x="56" y="80" xlink:href="#p" />
|
||||
<use x="56" y="96" xlink:href="#p" />
|
||||
<use x="56" y="104" xlink:href="#p" />
|
||||
<use x="56" y="112" xlink:href="#p" />
|
||||
<use x="56" y="128" xlink:href="#p" />
|
||||
<use x="56" y="144" xlink:href="#p" />
|
||||
<use x="56" y="160" xlink:href="#p" />
|
||||
<use x="56" y="168" xlink:href="#p" />
|
||||
<use x="56" y="176" xlink:href="#p" />
|
||||
<use x="56" y="192" xlink:href="#p" />
|
||||
<use x="64" y="32" xlink:href="#p" />
|
||||
<use x="64" y="48" xlink:href="#p" />
|
||||
<use x="64" y="56" xlink:href="#p" />
|
||||
<use x="64" y="64" xlink:href="#p" />
|
||||
<use x="64" y="80" xlink:href="#p" />
|
||||
<use x="64" y="96" xlink:href="#p" />
|
||||
<use x="64" y="104" xlink:href="#p" />
|
||||
<use x="64" y="112" xlink:href="#p" />
|
||||
<use x="64" y="120" xlink:href="#p" />
|
||||
<use x="64" y="144" xlink:href="#p" />
|
||||
<use x="64" y="160" xlink:href="#p" />
|
||||
<use x="64" y="168" xlink:href="#p" />
|
||||
<use x="64" y="176" xlink:href="#p" />
|
||||
<use x="64" y="192" xlink:href="#p" />
|
||||
<use x="72" y="32" xlink:href="#p" />
|
||||
<use x="72" y="80" xlink:href="#p" />
|
||||
<use x="72" y="104" xlink:href="#p" />
|
||||
<use x="72" y="120" xlink:href="#p" />
|
||||
<use x="72" y="144" xlink:href="#p" />
|
||||
<use x="72" y="192" xlink:href="#p" />
|
||||
<use x="80" y="32" xlink:href="#p" />
|
||||
<use x="80" y="40" xlink:href="#p" />
|
||||
<use x="80" y="48" xlink:href="#p" />
|
||||
<use x="80" y="56" xlink:href="#p" />
|
||||
<use x="80" y="64" xlink:href="#p" />
|
||||
<use x="80" y="72" xlink:href="#p" />
|
||||
<use x="80" y="80" xlink:href="#p" />
|
||||
<use x="80" y="96" xlink:href="#p" />
|
||||
<use x="80" y="112" xlink:href="#p" />
|
||||
<use x="80" y="128" xlink:href="#p" />
|
||||
<use x="80" y="144" xlink:href="#p" />
|
||||
<use x="80" y="152" xlink:href="#p" />
|
||||
<use x="80" y="160" xlink:href="#p" />
|
||||
<use x="80" y="168" xlink:href="#p" />
|
||||
<use x="80" y="176" xlink:href="#p" />
|
||||
<use x="80" y="184" xlink:href="#p" />
|
||||
<use x="80" y="192" xlink:href="#p" />
|
||||
<use x="88" y="96" xlink:href="#p" />
|
||||
<use x="88" y="104" xlink:href="#p" />
|
||||
<use x="88" y="112" xlink:href="#p" />
|
||||
<use x="88" y="128" xlink:href="#p" />
|
||||
<use x="96" y="40" xlink:href="#p" />
|
||||
<use x="96" y="56" xlink:href="#p" />
|
||||
<use x="96" y="72" xlink:href="#p" />
|
||||
<use x="96" y="80" xlink:href="#p" />
|
||||
<use x="96" y="96" xlink:href="#p" />
|
||||
<use x="96" y="136" xlink:href="#p" />
|
||||
<use x="96" y="144" xlink:href="#p" />
|
||||
<use x="96" y="160" xlink:href="#p" />
|
||||
<use x="96" y="168" xlink:href="#p" />
|
||||
<use x="96" y="176" xlink:href="#p" />
|
||||
<use x="96" y="184" xlink:href="#p" />
|
||||
<use x="96" y="192" xlink:href="#p" />
|
||||
<use x="104" y="40" xlink:href="#p" />
|
||||
<use x="104" y="56" xlink:href="#p" />
|
||||
<use x="104" y="64" xlink:href="#p" />
|
||||
<use x="104" y="88" xlink:href="#p" />
|
||||
<use x="104" y="120" xlink:href="#p" />
|
||||
<use x="104" y="128" xlink:href="#p" />
|
||||
<use x="104" y="136" xlink:href="#p" />
|
||||
<use x="104" y="144" xlink:href="#p" />
|
||||
<use x="104" y="152" xlink:href="#p" />
|
||||
<use x="104" y="160" xlink:href="#p" />
|
||||
<use x="104" y="168" xlink:href="#p" />
|
||||
<use x="104" y="176" xlink:href="#p" />
|
||||
<use x="112" y="32" xlink:href="#p" />
|
||||
<use x="112" y="40" xlink:href="#p" />
|
||||
<use x="112" y="48" xlink:href="#p" />
|
||||
<use x="112" y="80" xlink:href="#p" />
|
||||
<use x="112" y="104" xlink:href="#p" />
|
||||
<use x="112" y="112" xlink:href="#p" />
|
||||
<use x="112" y="128" xlink:href="#p" />
|
||||
<use x="112" y="144" xlink:href="#p" />
|
||||
<use x="112" y="184" xlink:href="#p" />
|
||||
<use x="112" y="192" xlink:href="#p" />
|
||||
<use x="120" y="32" xlink:href="#p" />
|
||||
<use x="120" y="48" xlink:href="#p" />
|
||||
<use x="120" y="72" xlink:href="#p" />
|
||||
<use x="120" y="96" xlink:href="#p" />
|
||||
<use x="120" y="104" xlink:href="#p" />
|
||||
<use x="120" y="120" xlink:href="#p" />
|
||||
<use x="120" y="144" xlink:href="#p" />
|
||||
<use x="120" y="160" xlink:href="#p" />
|
||||
<use x="120" y="168" xlink:href="#p" />
|
||||
<use x="120" y="184" xlink:href="#p" />
|
||||
<use x="128" y="32" xlink:href="#p" />
|
||||
<use x="128" y="40" xlink:href="#p" />
|
||||
<use x="128" y="48" xlink:href="#p" />
|
||||
<use x="128" y="56" xlink:href="#p" />
|
||||
<use x="128" y="64" xlink:href="#p" />
|
||||
<use x="128" y="80" xlink:href="#p" />
|
||||
<use x="128" y="104" xlink:href="#p" />
|
||||
<use x="128" y="112" xlink:href="#p" />
|
||||
<use x="128" y="120" xlink:href="#p" />
|
||||
<use x="128" y="128" xlink:href="#p" />
|
||||
<use x="128" y="136" xlink:href="#p" />
|
||||
<use x="128" y="168" xlink:href="#p" />
|
||||
<use x="128" y="176" xlink:href="#p" />
|
||||
<use x="128" y="184" xlink:href="#p" />
|
||||
<use x="128" y="192" xlink:href="#p" />
|
||||
<use x="136" y="96" xlink:href="#p" />
|
||||
<use x="136" y="104" xlink:href="#p" />
|
||||
<use x="136" y="112" xlink:href="#p" />
|
||||
<use x="136" y="120" xlink:href="#p" />
|
||||
<use x="136" y="136" xlink:href="#p" />
|
||||
<use x="136" y="168" xlink:href="#p" />
|
||||
<use x="136" y="184" xlink:href="#p" />
|
||||
<use x="144" y="32" xlink:href="#p" />
|
||||
<use x="144" y="40" xlink:href="#p" />
|
||||
<use x="144" y="48" xlink:href="#p" />
|
||||
<use x="144" y="56" xlink:href="#p" />
|
||||
<use x="144" y="64" xlink:href="#p" />
|
||||
<use x="144" y="72" xlink:href="#p" />
|
||||
<use x="144" y="80" xlink:href="#p" />
|
||||
<use x="144" y="128" xlink:href="#p" />
|
||||
<use x="144" y="168" xlink:href="#p" />
|
||||
<use x="144" y="176" xlink:href="#p" />
|
||||
<use x="144" y="184" xlink:href="#p" />
|
||||
<use x="152" y="32" xlink:href="#p" />
|
||||
<use x="152" y="80" xlink:href="#p" />
|
||||
<use x="152" y="96" xlink:href="#p" />
|
||||
<use x="152" y="136" xlink:href="#p" />
|
||||
<use x="152" y="152" xlink:href="#p" />
|
||||
<use x="152" y="168" xlink:href="#p" />
|
||||
<use x="152" y="192" xlink:href="#p" />
|
||||
<use x="160" y="32" xlink:href="#p" />
|
||||
<use x="160" y="48" xlink:href="#p" />
|
||||
<use x="160" y="56" xlink:href="#p" />
|
||||
<use x="160" y="64" xlink:href="#p" />
|
||||
<use x="160" y="80" xlink:href="#p" />
|
||||
<use x="160" y="104" xlink:href="#p" />
|
||||
<use x="160" y="120" xlink:href="#p" />
|
||||
<use x="160" y="128" xlink:href="#p" />
|
||||
<use x="160" y="136" xlink:href="#p" />
|
||||
<use x="160" y="160" xlink:href="#p" />
|
||||
<use x="160" y="168" xlink:href="#p" />
|
||||
<use x="160" y="184" xlink:href="#p" />
|
||||
<use x="168" y="32" xlink:href="#p" />
|
||||
<use x="168" y="48" xlink:href="#p" />
|
||||
<use x="168" y="56" xlink:href="#p" />
|
||||
<use x="168" y="64" xlink:href="#p" />
|
||||
<use x="168" y="80" xlink:href="#p" />
|
||||
<use x="168" y="96" xlink:href="#p" />
|
||||
<use x="168" y="104" xlink:href="#p" />
|
||||
<use x="168" y="112" xlink:href="#p" />
|
||||
<use x="168" y="120" xlink:href="#p" />
|
||||
<use x="168" y="128" xlink:href="#p" />
|
||||
<use x="168" y="152" xlink:href="#p" />
|
||||
<use x="168" y="160" xlink:href="#p" />
|
||||
<use x="168" y="168" xlink:href="#p" />
|
||||
<use x="168" y="184" xlink:href="#p" />
|
||||
<use x="176" y="32" xlink:href="#p" />
|
||||
<use x="176" y="48" xlink:href="#p" />
|
||||
<use x="176" y="56" xlink:href="#p" />
|
||||
<use x="176" y="64" xlink:href="#p" />
|
||||
<use x="176" y="80" xlink:href="#p" />
|
||||
<use x="176" y="104" xlink:href="#p" />
|
||||
<use x="176" y="112" xlink:href="#p" />
|
||||
<use x="176" y="120" xlink:href="#p" />
|
||||
<use x="176" y="144" xlink:href="#p" />
|
||||
<use x="176" y="152" xlink:href="#p" />
|
||||
<use x="176" y="168" xlink:href="#p" />
|
||||
<use x="176" y="176" xlink:href="#p" />
|
||||
<use x="176" y="184" xlink:href="#p" />
|
||||
<use x="184" y="32" xlink:href="#p" />
|
||||
<use x="184" y="80" xlink:href="#p" />
|
||||
<use x="184" y="96" xlink:href="#p" />
|
||||
<use x="184" y="112" xlink:href="#p" />
|
||||
<use x="184" y="128" xlink:href="#p" />
|
||||
<use x="184" y="144" xlink:href="#p" />
|
||||
<use x="184" y="152" xlink:href="#p" />
|
||||
<use x="184" y="192" xlink:href="#p" />
|
||||
<use x="192" y="32" xlink:href="#p" />
|
||||
<use x="192" y="40" xlink:href="#p" />
|
||||
<use x="192" y="48" xlink:href="#p" />
|
||||
<use x="192" y="56" xlink:href="#p" />
|
||||
<use x="192" y="64" xlink:href="#p" />
|
||||
<use x="192" y="72" xlink:href="#p" />
|
||||
<use x="192" y="80" xlink:href="#p" />
|
||||
<use x="192" y="104" xlink:href="#p" />
|
||||
<use x="192" y="120" xlink:href="#p" />
|
||||
<use x="192" y="128" xlink:href="#p" />
|
||||
<use x="192" y="160" xlink:href="#p" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
|
@ -14,6 +14,5 @@
|
|||
|
||||
<application
|
||||
android:testOnly="false"
|
||||
android:allowBackup="false"
|
||||
tools:ignore="GoogleAppIndexingWarning"/>
|
||||
</manifest>
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<!-- WRITE_EXTERNAL_STORAGE may be enabled or disabled by the user after installation in
|
||||
API >= 23; the app needs to handle this -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- Next permissions are always approved in installation time, the apps needs to do nothing special in runtime -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
@ -70,6 +71,7 @@
|
|||
must request the FOREGROUND_SERVICE permission -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.blikoon.qrcodescanner" />
|
||||
|
||||
<application
|
||||
android:name=".MainApp"
|
||||
|
@ -274,11 +276,24 @@
|
|||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".authentication.DeepLinkLoginActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:theme="@style/Theme.ownCloud.noActionBar.Login">
|
||||
<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="@string/login_data_own_scheme" android:host="login"/>
|
||||
|
||||
<data
|
||||
android:host="login"
|
||||
android:scheme="@string/login_data_own_scheme" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
package com.owncloud.android.authentication;
|
||||
|
||||
import android.Manifest;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.SuppressLint;
|
||||
|
@ -50,6 +51,7 @@ import android.content.Intent;
|
|||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
|
@ -83,6 +85,7 @@ import android.widget.ProgressBar;
|
|||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
||||
import com.blikoon.qrcodescanner.QrCodeActivity;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.owncloud.android.MainApp;
|
||||
|
@ -110,6 +113,7 @@ import com.owncloud.android.operations.GetServerInfoOperation;
|
|||
import com.owncloud.android.operations.OAuth2GetAccessToken;
|
||||
import com.owncloud.android.services.OperationsService;
|
||||
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.activity.FirstRunActivity;
|
||||
import com.owncloud.android.ui.components.CustomEditText;
|
||||
import com.owncloud.android.ui.dialog.CredentialsDialogFragment;
|
||||
|
@ -119,6 +123,7 @@ import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
|
|||
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.ErrorMessageAdapter;
|
||||
import com.owncloud.android.utils.PermissionUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URLDecoder;
|
||||
|
@ -127,6 +132,7 @@ import java.util.HashMap;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
@ -191,6 +197,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
public static final int NO_ICON = 0;
|
||||
public static final String EMPTY_STRING = "";
|
||||
|
||||
private static final int REQUEST_CODE_QR_SCAN = 101;
|
||||
|
||||
|
||||
/// parameters from EXTRAs in starter Intent
|
||||
private byte mAction;
|
||||
private Account mAccount;
|
||||
|
@ -261,7 +270,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
//Log_OC.e(TAG, "onCreate init");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
Uri data = getIntent().getData();
|
||||
boolean directLogin = data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme));
|
||||
if (savedInstanceState == null && !directLogin) {
|
||||
FirstRunActivity.runIfNeeded(this);
|
||||
}
|
||||
|
||||
|
@ -320,21 +331,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
/// initialize general UI elements
|
||||
initOverallUi();
|
||||
|
||||
findViewById(R.id.centeredRefreshButton).setOnClickListener(new View.OnClickListener() {
|
||||
findViewById(R.id.centeredRefreshButton).setOnClickListener(v -> checkOcServer());
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkOcServer();
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.embeddedRefreshButton).setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkOcServer();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.embeddedRefreshButton).setOnClickListener(v -> checkOcServer());
|
||||
|
||||
/// initialize block to be moved to single Fragment to check server and get info about it
|
||||
|
||||
|
@ -404,41 +403,35 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
// show snackbar after 60s to switch back to old login method
|
||||
if (showLegacyLogin) {
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DisplayUtils.createSnackbar(mLoginWebView, R.string.fallback_weblogin_text, Snackbar.LENGTH_INDEFINITE)
|
||||
.setActionTextColor(getResources().getColor(R.color.primary_dark))
|
||||
.setAction(R.string.fallback_weblogin_back, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mLoginWebView.setVisibility(View.INVISIBLE);
|
||||
webViewLoginMethod = false;
|
||||
new Handler().postDelayed(() -> DisplayUtils.createSnackbar(mLoginWebView,
|
||||
R.string.fallback_weblogin_text,
|
||||
Snackbar.LENGTH_INDEFINITE)
|
||||
.setActionTextColor(getResources().getColor(R.color.primary_dark))
|
||||
.setAction(R.string.fallback_weblogin_back, v -> {
|
||||
mLoginWebView.setVisibility(View.INVISIBLE);
|
||||
webViewLoginMethod = false;
|
||||
|
||||
setContentView(R.layout.account_setup);
|
||||
setContentView(R.layout.account_setup);
|
||||
|
||||
// initialize general UI elements
|
||||
initOverallUi();
|
||||
// initialize general UI elements
|
||||
initOverallUi();
|
||||
|
||||
mPasswordInputLayout.setVisibility(View.VISIBLE);
|
||||
mUsernameInputLayout.setVisibility(View.VISIBLE);
|
||||
mUsernameInput.requestFocus();
|
||||
mOAuth2Check.setVisibility(View.INVISIBLE);
|
||||
mAuthStatusView.setVisibility(View.INVISIBLE);
|
||||
mServerStatusView.setVisibility(View.INVISIBLE);
|
||||
mTestServerButton.setVisibility(View.INVISIBLE);
|
||||
forceOldLoginMethod = true;
|
||||
mOkButton.setVisibility(View.VISIBLE);
|
||||
mPasswordInputLayout.setVisibility(View.VISIBLE);
|
||||
mUsernameInputLayout.setVisibility(View.VISIBLE);
|
||||
mUsernameInput.requestFocus();
|
||||
mOAuth2Check.setVisibility(View.INVISIBLE);
|
||||
mAuthStatusView.setVisibility(View.INVISIBLE);
|
||||
mServerStatusView.setVisibility(View.INVISIBLE);
|
||||
mTestServerButton.setVisibility(View.INVISIBLE);
|
||||
forceOldLoginMethod = true;
|
||||
mOkButton.setVisibility(View.VISIBLE);
|
||||
|
||||
initServerPreFragment(null);
|
||||
initServerPreFragment(null);
|
||||
|
||||
mHostUrlInput.setText(baseURL);
|
||||
mHostUrlInput.setText(baseURL);
|
||||
|
||||
checkOcServer();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}, 60 * 1000);
|
||||
checkOcServer();
|
||||
}).show(), 60 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -512,9 +505,15 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
|
||||
|
||||
if (loginUrlInfo != null) {
|
||||
mServerInfo.mBaseUrl = AuthenticatorUrlUtils.normalizeUrlSuffix(loginUrlInfo.serverAddress);
|
||||
webViewUser = loginUrlInfo.username;
|
||||
webViewPassword = loginUrlInfo.password;
|
||||
try {
|
||||
mServerInfo.mBaseUrl = AuthenticatorUrlUtils.normalizeUrlSuffix(loginUrlInfo.serverAddress);
|
||||
webViewUser = loginUrlInfo.username;
|
||||
webViewPassword = loginUrlInfo.password;
|
||||
} catch (Exception e) {
|
||||
mServerStatusIcon = R.drawable.ic_alert;
|
||||
mServerStatusText = "QR Code could not be read!";
|
||||
showServerStatus();
|
||||
}
|
||||
checkOcServer();
|
||||
}
|
||||
}
|
||||
|
@ -583,14 +582,19 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
|
||||
private void initAuthTokenType() {
|
||||
mAuthTokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);
|
||||
Bundle extras = getIntent().getExtras();
|
||||
mAuthTokenType = null;
|
||||
|
||||
if (extras != null) {
|
||||
extras.getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);
|
||||
}
|
||||
|
||||
if (mAuthTokenType == null) {
|
||||
if (mAccount != null) {
|
||||
boolean oAuthRequired = mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null;
|
||||
boolean samlWebSsoRequired = mAccountMgr.getUserData
|
||||
(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
|
||||
mAuthTokenType = chooseAuthTokenType(oAuthRequired, samlWebSsoRequired);
|
||||
|
||||
} else {
|
||||
boolean oAuthSupported = AUTH_ON.equals(getString(R.string.auth_method_oauth2));
|
||||
boolean samlWebSsoSupported = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));
|
||||
|
@ -627,6 +631,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mOkButton = findViewById(R.id.buttonOK);
|
||||
mOkButton.setOnClickListener(v -> onOkClick());
|
||||
|
||||
findViewById(R.id.scanQR).setOnClickListener(v -> onScan());
|
||||
|
||||
setupInstructionMessage();
|
||||
|
||||
mTestServerButton.setVisibility(mAction == ACTION_CREATE ? View.VISIBLE : View.GONE);
|
||||
|
@ -763,17 +769,14 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
|
||||
// TODO find out if this is really necessary, or if it can done in a different way
|
||||
findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN &&
|
||||
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(
|
||||
MainApp.getAccountType(getBaseContext())).equals(mAuthTokenType) &&
|
||||
mHostUrlInput.hasFocus()) {
|
||||
checkOcServer();
|
||||
}
|
||||
return false;
|
||||
findViewById(R.id.scroll).setOnTouchListener((view, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN &&
|
||||
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(
|
||||
MainApp.getAccountType(getBaseContext())).equals(mAuthTokenType) &&
|
||||
mHostUrlInput.hasFocus()) {
|
||||
checkOcServer();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -980,6 +983,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mNewCapturedUriFromOAuth2Redirection = data;
|
||||
}
|
||||
|
||||
if (data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme))) {
|
||||
parseAndLoginFromWebView(data.toString());
|
||||
}
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
|
||||
webViewLoginMethod = true;
|
||||
setContentView(R.layout.account_setup_webview);
|
||||
|
@ -1757,6 +1764,14 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
if (success) {
|
||||
finish();
|
||||
|
||||
AccountUtils.setCurrentOwnCloudAccount(this, mAccount.name);
|
||||
|
||||
Intent i = new Intent(this, FileDisplayActivity.class);
|
||||
i.setAction(FileDisplayActivity.RESTART);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(i);
|
||||
|
||||
} else {
|
||||
// init webView again
|
||||
if (mLoginWebView != null) {
|
||||
|
@ -1804,9 +1819,31 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
} else { // authorization fail due to client side - probably wrong credentials
|
||||
if (webViewLoginMethod) {
|
||||
mLoginWebView = findViewById(R.id.login_webview);
|
||||
initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, true, false);
|
||||
|
||||
DisplayUtils.showSnackMessage(this, mLoginWebView, R.string.auth_access_failed, result.getLogMessage());
|
||||
if (mLoginWebView != null) {
|
||||
initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, true, false);
|
||||
DisplayUtils.showSnackMessage(this, mLoginWebView, R.string.auth_access_failed,
|
||||
result.getLogMessage());
|
||||
} else {
|
||||
DisplayUtils.showSnackMessage(this, R.string.auth_access_failed, result.getLogMessage());
|
||||
|
||||
// init webView again
|
||||
if (mLoginWebView != null) {
|
||||
mLoginWebView.setVisibility(View.GONE);
|
||||
}
|
||||
setContentView(R.layout.account_setup);
|
||||
|
||||
initOverallUi();
|
||||
|
||||
CustomEditText serverAddressField = findViewById(R.id.hostUrlInput);
|
||||
serverAddressField.setText(mServerInfo.mBaseUrl);
|
||||
|
||||
findViewById(R.id.oauth_onOff_check).setVisibility(View.GONE);
|
||||
findViewById(R.id.server_status_text).setVisibility(View.GONE);
|
||||
mAuthStatusView = findViewById(R.id.auth_status_text);
|
||||
|
||||
showAuthStatus();
|
||||
}
|
||||
} else {
|
||||
updateAuthStatusIconAndText(result);
|
||||
showAuthStatus();
|
||||
|
@ -1978,6 +2015,40 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
}
|
||||
|
||||
public void onScan() {
|
||||
if (PermissionUtil.checkSelfPermission(this, Manifest.permission.CAMERA)) {
|
||||
startQRScanner();
|
||||
} else {
|
||||
PermissionUtil.requestCameraPermission(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void startQRScanner() {
|
||||
Intent i = new Intent(AuthenticatorActivity.this, QrCodeActivity.class);
|
||||
startActivityForResult(i, REQUEST_CODE_QR_SCAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
|
||||
@NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PermissionUtil.PERMISSIONS_CAMERA: {
|
||||
// If request is cancelled, result arrays are empty.
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// permission was granted
|
||||
startQRScanner();
|
||||
} else {
|
||||
// permission denied
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Updates the content and visibility state of the icon and text associated
|
||||
|
@ -2256,10 +2327,27 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
)) {
|
||||
mOperationsServiceBinder = (OperationsServiceBinder) service;
|
||||
|
||||
doOnResumeAndBound();
|
||||
Uri data = getIntent().getData();
|
||||
if (data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme))) {
|
||||
String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
|
||||
LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, data.toString());
|
||||
|
||||
if (loginUrlInfo != null) {
|
||||
try {
|
||||
mServerInfo.mBaseUrl = AuthenticatorUrlUtils.normalizeUrlSuffix(loginUrlInfo.serverAddress);
|
||||
webViewUser = loginUrlInfo.username;
|
||||
webViewPassword = loginUrlInfo.password;
|
||||
doOnResumeAndBound();
|
||||
} catch (Exception e) {
|
||||
mServerStatusIcon = R.drawable.ic_alert;
|
||||
mServerStatusText = "QR Code could not be read!";
|
||||
showServerStatus();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
doOnResumeAndBound();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2302,4 +2390,24 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
public void doNegativeAuthenticationDialogClick() {
|
||||
mIsFirstAuthAttempt = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
if (requestCode == REQUEST_CODE_QR_SCAN) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String result = data.getStringExtra("com.blikoon.qrcodescanner.got_qr_scan_relult");
|
||||
|
||||
if (!result.startsWith(getString(R.string.login_data_own_scheme))) {
|
||||
mServerStatusIcon = R.drawable.ic_alert;
|
||||
mServerStatusText = "QR Code could not be read!";
|
||||
showServerStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
parseAndLoginFromWebView(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.owncloud.android.authentication;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
public class DeepLinkLoginActivity extends AuthenticatorActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.deep_link_login);
|
||||
|
||||
Uri data = getIntent().getData();
|
||||
|
||||
if (data != null) {
|
||||
String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
|
||||
LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, data.toString());
|
||||
|
||||
TextView loginText = findViewById(R.id.loginInfo);
|
||||
loginText.setTextColor(ThemeUtils.fontColor(this));
|
||||
loginText.setText(String.format("Login with %1$s to %2$s", loginUrlInfo.username,
|
||||
loginUrlInfo.serverAddress));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -740,8 +740,7 @@ public class OperationsService extends Service {
|
|||
final RemoteOperation operation, final RemoteOperationResult result
|
||||
) {
|
||||
int count = 0;
|
||||
Iterator<OnRemoteOperationListener> listeners =
|
||||
mOperationsBinder.mBoundListeners.keySet().iterator();
|
||||
Iterator<OnRemoteOperationListener> listeners = mOperationsBinder.mBoundListeners.keySet().iterator();
|
||||
while (listeners.hasNext()) {
|
||||
final OnRemoteOperationListener listener = listeners.next();
|
||||
final Handler handler = mOperationsBinder.mBoundListeners.get(listener);
|
||||
|
|
|
@ -15,6 +15,7 @@ public final class PermissionUtil {
|
|||
public static final int PERMISSIONS_READ_CONTACTS_AUTOMATIC = 2;
|
||||
public static final int PERMISSIONS_READ_CONTACTS_MANUALLY = 3;
|
||||
public static final int PERMISSIONS_WRITE_CONTACTS = 4;
|
||||
public static final int PERMISSIONS_CAMERA = 5;
|
||||
|
||||
private PermissionUtil() {
|
||||
// utility class -> private constructor
|
||||
|
@ -57,4 +58,15 @@ public final class PermissionUtil {
|
|||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSIONS_WRITE_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* request camera permission.
|
||||
*
|
||||
* @param activity The target activity.
|
||||
*/
|
||||
public static void requestCameraPermission(Activity activity) {
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{Manifest.permission.CAMERA},
|
||||
PERMISSIONS_CAMERA);
|
||||
}
|
||||
}
|
||||
|
|
717
src/main/res/drawable/ic_qrcode.xml
Normal file
717
src/main/res/drawable/ic_qrcode.xml
Normal file
|
@ -0,0 +1,717 @@
|
|||
<vector android:height="72dp"
|
||||
android:viewportHeight="232"
|
||||
android:viewportWidth="232"
|
||||
android:width="72dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M0,0h232v232h-232z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,72h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,152h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M32,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M40,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M40,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M40,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M40,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M40,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M40,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M48,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M56,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M64,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M72,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M72,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M72,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M72,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M72,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M72,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,72h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,152h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M80,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M88,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M88,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M88,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M88,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,72h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,136h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M96,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,88h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,136h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,152h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M104,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M112,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,72h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M120,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,136h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M128,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,136h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M136,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,40h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,72h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M144,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,136h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,152h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M152,192h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,136h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M160,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,96h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,128h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,152h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,160h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M168,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,48h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,56h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,64h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,80h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,104h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,112h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,120h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,144h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,152h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,168h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,176h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M176,184h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M184,32h8v8h-8z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|