1
0
Fork 0
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:
tobiasKaminsky 2018-11-29 10:37:30 +01:00 committed by Andy Scherzinger
parent 24cff7db24
commit d47c77ca5c
No known key found for this signature in database
GPG key ID: 6CADC7E3523C308B
14 changed files with 1276 additions and 68 deletions

View file

@ -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'

View 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

View file

@ -14,6 +14,5 @@
<application
android:testOnly="false"
android:allowBackup="false"
tools:ignore="GoogleAppIndexingWarning"/>
</manifest>

View file

@ -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>

View file

@ -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);
}
}
}

View file

@ -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));
}
}
}

View file

@ -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);

View file

@ -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);
}
}

View 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"