Preferences.java 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. /*
  2. * ownCloud Android client application
  3. *
  4. * @author Bartek Przybylski
  5. * @author David A. Velasco
  6. * Copyright (C) 2011 Bartek Przybylski
  7. * Copyright (C) 2016 ownCloud Inc.
  8. * Copyright (C) 2016 Nextcloud
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. package com.owncloud.android.ui.activity;
  24. import android.accounts.Account;
  25. import android.accounts.AuthenticatorException;
  26. import android.accounts.OperationCanceledException;
  27. import android.app.Activity;
  28. import android.content.Intent;
  29. import android.content.SharedPreferences;
  30. import android.content.pm.PackageInfo;
  31. import android.content.pm.PackageManager.NameNotFoundException;
  32. import android.content.res.Configuration;
  33. import android.graphics.drawable.ColorDrawable;
  34. import android.graphics.drawable.Drawable;
  35. import android.net.Uri;
  36. import android.os.AsyncTask;
  37. import android.os.Build;
  38. import android.os.Bundle;
  39. import android.os.Environment;
  40. import android.preference.ListPreference;
  41. import android.preference.Preference;
  42. import android.preference.Preference.OnPreferenceChangeListener;
  43. import android.preference.Preference.OnPreferenceClickListener;
  44. import android.preference.PreferenceActivity;
  45. import android.preference.PreferenceCategory;
  46. import android.preference.PreferenceManager;
  47. import android.preference.PreferenceScreen;
  48. import android.preference.SwitchPreference;
  49. import android.support.annotation.LayoutRes;
  50. import android.support.design.widget.Snackbar;
  51. import android.support.v4.content.res.ResourcesCompat;
  52. import android.support.v7.app.ActionBar;
  53. import android.support.v7.app.AppCompatDelegate;
  54. import android.view.Menu;
  55. import android.view.MenuInflater;
  56. import android.view.MenuItem;
  57. import android.view.View;
  58. import android.view.ViewGroup;
  59. import android.webkit.URLUtil;
  60. import com.owncloud.android.BuildConfig;
  61. import com.owncloud.android.MainApp;
  62. import com.owncloud.android.R;
  63. import com.owncloud.android.authentication.AccountUtils;
  64. import com.owncloud.android.datamodel.ArbitraryDataProvider;
  65. import com.owncloud.android.datamodel.ExternalLinksProvider;
  66. import com.owncloud.android.datastorage.DataStorageProvider;
  67. import com.owncloud.android.datastorage.StoragePoint;
  68. import com.owncloud.android.lib.common.ExternalLink;
  69. import com.owncloud.android.lib.common.ExternalLinkType;
  70. import com.owncloud.android.lib.common.OwnCloudAccount;
  71. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  72. import com.owncloud.android.lib.common.utils.Log_OC;
  73. import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask;
  74. import com.owncloud.android.utils.AnalyticsUtils;
  75. import com.owncloud.android.utils.DisplayUtils;
  76. import com.owncloud.android.utils.MimeTypeUtil;
  77. import com.owncloud.android.utils.ThemeUtils;
  78. import java.io.BufferedReader;
  79. import java.io.IOException;
  80. import java.util.concurrent.ExecutionException;
  81. /**
  82. * An Activity that allows the user to change the application's settings.
  83. *
  84. * It proxies the necessary calls via {@link android.support.v7.app.AppCompatDelegate} to be used with AppCompat.
  85. */
  86. public class Preferences extends PreferenceActivity
  87. implements StorageMigration.StorageMigrationProgressListener {
  88. private static final String TAG = Preferences.class.getSimpleName();
  89. public final static String PREFERENCE_USE_FINGERPRINT = "use_fingerprint";
  90. public static final String PREFERENCE_EXPERT_MODE = "expert_mode";
  91. private static final String SCREEN_NAME = "Settings";
  92. private static final int ACTION_REQUEST_PASSCODE = 5;
  93. private static final int ACTION_CONFIRM_PASSCODE = 6;
  94. private static final int ACTION_REQUEST_CODE_DAVDROID_SETUP = 10;
  95. private static final String DAV_PATH = "/remote.php/dav";
  96. public static final String SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI = "SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI";
  97. /**
  98. * The user's server base uri.
  99. */
  100. private Uri mUri;
  101. private SwitchPreference pCode;
  102. private SwitchPreference fPrint;
  103. private SwitchPreference mShowHiddenFiles;
  104. private SwitchPreference mExpertMode;
  105. private Preference pAboutApp;
  106. private AppCompatDelegate mDelegate;
  107. private ListPreference mPrefStoragePath;
  108. private String mStoragePath;
  109. public static class PreferenceKeys {
  110. public static final String STORAGE_PATH = "storage_path";
  111. public static final String INSTANT_UPLOAD_PATH = "instant_upload_path";
  112. public static final String INSTANT_VIDEO_UPLOAD_PATH = "instant_video_upload_path";
  113. }
  114. @SuppressWarnings("deprecation")
  115. @Override
  116. public void onCreate(Bundle savedInstanceState) {
  117. if (ThemeUtils.themingEnabled()) {
  118. setTheme(R.style.FallbackThemingTheme);
  119. }
  120. getDelegate().installViewFactory();
  121. getDelegate().onCreate(savedInstanceState);
  122. super.onCreate(savedInstanceState);
  123. addPreferencesFromResource(R.xml.preferences);
  124. // retrieve user's base uri
  125. setupBaseUri();
  126. setupActionBar();
  127. // Register context menu for list of preferences.
  128. registerForContextMenu(getListView());
  129. int accentColor = ThemeUtils.primaryAccentColor();
  130. String appVersion = getAppVersion();
  131. PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference("preference_screen");
  132. // General
  133. setupGeneralCategory(accentColor);
  134. // Synced folders
  135. setupAutoUploadCategory(accentColor, preferenceScreen);
  136. // Details
  137. setupDetailsCategory(accentColor, preferenceScreen);
  138. // More
  139. setupMoreCategory(accentColor, appVersion);
  140. // About
  141. setupAboutCategory(accentColor, appVersion);
  142. // Dev
  143. setupDevCategory(accentColor, preferenceScreen);
  144. }
  145. private void setupDevCategory(int accentColor, PreferenceScreen preferenceScreen) {
  146. // Dev category
  147. PreferenceCategory preferenceCategoryDev = (PreferenceCategory) findPreference("dev_category");
  148. if (getResources().getBoolean(R.bool.is_beta)) {
  149. preferenceCategoryDev.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_category_dev),
  150. accentColor));
  151. /* Link to dev apks */
  152. Preference pDevLink = findPreference("dev_link");
  153. if (pDevLink != null) {
  154. if (getResources().getBoolean(R.bool.dev_version_direct_download_enabled)) {
  155. pDevLink.setOnPreferenceClickListener(preference -> {
  156. Integer latestVersion = -1;
  157. Integer currentVersion = -1;
  158. try {
  159. currentVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
  160. String url = getString(R.string.dev_latest);
  161. LoadingVersionNumberTask loadTask = new LoadingVersionNumberTask();
  162. loadTask.execute(url);
  163. latestVersion = loadTask.get();
  164. } catch (InterruptedException | ExecutionException | NameNotFoundException e) {
  165. Log_OC.e(TAG, "Error detecting app version", e);
  166. }
  167. if (latestVersion == -1 || currentVersion == -1) {
  168. Snackbar.make(getListView(), R.string.dev_version_no_information_available,
  169. Snackbar.LENGTH_SHORT).show();
  170. }
  171. if (latestVersion > currentVersion) {
  172. String devApkLink = (String) getText(R.string.dev_link) + latestVersion + ".apk";
  173. Uri uriUrl = Uri.parse(devApkLink);
  174. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  175. startActivity(intent);
  176. return true;
  177. } else {
  178. Snackbar.make(getListView(), R.string.dev_version_no_new_version_available,
  179. Snackbar.LENGTH_SHORT).show();
  180. return true;
  181. }
  182. });
  183. } else {
  184. preferenceCategoryDev.removePreference(pDevLink);
  185. }
  186. }
  187. /* Link to dev changelog */
  188. Preference pChangelogLink = findPreference("changelog_link");
  189. if (pChangelogLink != null) {
  190. pChangelogLink.setOnPreferenceClickListener(preference -> {
  191. String devChangelogLink = getString(R.string.dev_changelog);
  192. Uri uriUrl = Uri.parse(devChangelogLink);
  193. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  194. startActivity(intent);
  195. return true;
  196. });
  197. }
  198. } else {
  199. preferenceScreen.removePreference(preferenceCategoryDev);
  200. }
  201. }
  202. private void setupAboutCategory(int accentColor, String appVersion) {
  203. PreferenceCategory preferenceCategoryAbout = (PreferenceCategory) findPreference("about");
  204. preferenceCategoryAbout.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_category_about),
  205. accentColor));
  206. /* About App */
  207. pAboutApp = findPreference("about_app");
  208. if (pAboutApp != null) {
  209. pAboutApp.setTitle(String.format(getString(R.string.about_android), getString(R.string.app_name)));
  210. pAboutApp.setSummary(String.format(getString(R.string.about_version), appVersion));
  211. }
  212. // license
  213. boolean licenseEnabled = getResources().getBoolean(R.bool.license_enabled);
  214. Preference licensePreference = findPreference("license");
  215. if (licensePreference != null) {
  216. String licenseUrl = getString(R.string.license_url);
  217. if (licenseEnabled && !licenseUrl.isEmpty()) {
  218. licensePreference.setSummary(R.string.prefs_gpl_v2);
  219. licensePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  220. @Override
  221. public boolean onPreferenceClick(Preference preference) {
  222. Uri uriUrl = Uri.parse(licenseUrl);
  223. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  224. startActivity(intent);
  225. return true;
  226. }
  227. });
  228. } else {
  229. preferenceCategoryAbout.removePreference(licensePreference);
  230. }
  231. }
  232. // privacy
  233. boolean privacyEnabled = getResources().getBoolean(R.bool.privacy_enabled);
  234. Preference privacyPreference = findPreference("privacy");
  235. if (privacyPreference != null) {
  236. if (privacyEnabled && URLUtil.isValidUrl(getString(R.string.privacy_url))) {
  237. privacyPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  238. @Override
  239. public boolean onPreferenceClick(Preference preference) {
  240. try {
  241. Uri privacyUrl = Uri.parse(getString(R.string.privacy_url));
  242. String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(privacyUrl.getLastPathSegment());
  243. Intent intent;
  244. if ("application/pdf".equals(mimeType)) {
  245. intent = new Intent(Intent.ACTION_VIEW, privacyUrl);
  246. } else {
  247. intent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
  248. intent.putExtra(ExternalSiteWebView.EXTRA_TITLE,
  249. getResources().getString(R.string.privacy));
  250. intent.putExtra(ExternalSiteWebView.EXTRA_URL, privacyUrl.toString());
  251. intent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
  252. intent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, -1);
  253. }
  254. startActivity(intent);
  255. } catch (Exception e) {
  256. Log_OC.e(TAG, "Could not parse privacy url");
  257. preferenceCategoryAbout.removePreference(privacyPreference);
  258. }
  259. return true;
  260. }
  261. });
  262. } else {
  263. preferenceCategoryAbout.removePreference(privacyPreference);
  264. }
  265. }
  266. // source code
  267. boolean sourcecodeEnabled = getResources().getBoolean(R.bool.sourcecode_enabled);
  268. Preference sourcecodePreference = findPreference("sourcecode");
  269. if (sourcecodePreference != null) {
  270. String sourcecodeUrl = getString(R.string.sourcecode_url);
  271. if (sourcecodeEnabled && !sourcecodeUrl.isEmpty()) {
  272. sourcecodePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  273. @Override
  274. public boolean onPreferenceClick(Preference preference) {
  275. Uri uriUrl = Uri.parse(sourcecodeUrl);
  276. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  277. startActivity(intent);
  278. return true;
  279. }
  280. });
  281. } else {
  282. preferenceCategoryAbout.removePreference(sourcecodePreference);
  283. }
  284. }
  285. }
  286. private void setupMoreCategory(int accentColor, String appVersion) {
  287. PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more");
  288. preferenceCategoryMore.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_category_more),
  289. accentColor));
  290. setupCalendarPreference(preferenceCategoryMore);
  291. setupContactsBackupPreference(preferenceCategoryMore);
  292. setupHelpPreference(preferenceCategoryMore);
  293. setupRecommendPreference(preferenceCategoryMore);
  294. setupFeedbackPreference(appVersion, preferenceCategoryMore);
  295. setupLoggingPreference(preferenceCategoryMore);
  296. setupImprintPreference(preferenceCategoryMore);
  297. loadExternalSettingLinks(preferenceCategoryMore);
  298. }
  299. private void setupImprintPreference(PreferenceCategory preferenceCategoryMore) {
  300. boolean imprintEnabled = getResources().getBoolean(R.bool.imprint_enabled);
  301. Preference pImprint = findPreference("imprint");
  302. if (pImprint != null) {
  303. if (imprintEnabled) {
  304. pImprint.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  305. @Override
  306. public boolean onPreferenceClick(Preference preference) {
  307. String imprintWeb = getString(R.string.url_imprint);
  308. if (imprintWeb != null && imprintWeb.length() > 0) {
  309. Uri uriUrl = Uri.parse(imprintWeb);
  310. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  311. startActivity(intent);
  312. }
  313. //ImprintDialog.newInstance(true).show(preference.get, "IMPRINT_DIALOG");
  314. return true;
  315. }
  316. });
  317. } else {
  318. preferenceCategoryMore.removePreference(pImprint);
  319. }
  320. }
  321. }
  322. private void setupLoggingPreference(PreferenceCategory preferenceCategoryMore) {
  323. SharedPreferences appPrefs =
  324. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  325. boolean loggerEnabled = getResources().getBoolean(R.bool.logger_enabled) || BuildConfig.DEBUG ||
  326. appPrefs.getBoolean(PREFERENCE_EXPERT_MODE, false);
  327. Preference pLogger = findPreference("logger");
  328. if (pLogger != null) {
  329. if (loggerEnabled) {
  330. pLogger.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  331. @Override
  332. public boolean onPreferenceClick(Preference preference) {
  333. Intent loggerIntent = new Intent(getApplicationContext(), LogHistoryActivity.class);
  334. startActivity(loggerIntent);
  335. return true;
  336. }
  337. });
  338. } else {
  339. preferenceCategoryMore.removePreference(pLogger);
  340. }
  341. }
  342. }
  343. private void setupFeedbackPreference(String appVersion, PreferenceCategory preferenceCategoryMore) {
  344. boolean feedbackEnabled = getResources().getBoolean(R.bool.feedback_enabled);
  345. Preference pFeedback = findPreference("feedback");
  346. if (pFeedback != null) {
  347. if (feedbackEnabled) {
  348. pFeedback.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  349. @Override
  350. public boolean onPreferenceClick(Preference preference) {
  351. String feedbackMail = getString(R.string.mail_feedback);
  352. String feedback = getText(R.string.prefs_feedback) + " - android v" + appVersion;
  353. Intent intent = new Intent(Intent.ACTION_SENDTO);
  354. intent.setType("text/plain");
  355. intent.putExtra(Intent.EXTRA_SUBJECT, feedback);
  356. intent.setData(Uri.parse(feedbackMail));
  357. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  358. startActivity(intent);
  359. return true;
  360. }
  361. });
  362. } else {
  363. preferenceCategoryMore.removePreference(pFeedback);
  364. }
  365. }
  366. }
  367. private void setupRecommendPreference(PreferenceCategory preferenceCategoryMore) {
  368. boolean recommendEnabled = getResources().getBoolean(R.bool.recommend_enabled);
  369. Preference pRecommend = findPreference("recommend");
  370. if (pRecommend != null) {
  371. if (recommendEnabled) {
  372. pRecommend.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  373. @Override
  374. public boolean onPreferenceClick(Preference preference) {
  375. Intent intent = new Intent(Intent.ACTION_SEND);
  376. intent.setType("text/plain");
  377. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  378. String appName = getString(R.string.app_name);
  379. String downloadUrlGooglePlayStore = getString(R.string.url_app_download);
  380. String downloadUrlFDroid = getString(R.string.fdroid_link);
  381. String downloadUrls = String.format(getString(R.string.recommend_urls),
  382. downloadUrlGooglePlayStore, downloadUrlFDroid);
  383. String recommendSubject = String.format(getString(R.string.recommend_subject), appName);
  384. String recommendText = String.format(getString(R.string.recommend_text),
  385. appName, downloadUrls);
  386. intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject);
  387. intent.putExtra(Intent.EXTRA_TEXT, recommendText);
  388. startActivity(intent);
  389. return true;
  390. }
  391. });
  392. } else {
  393. preferenceCategoryMore.removePreference(pRecommend);
  394. }
  395. }
  396. }
  397. private void setupHelpPreference(PreferenceCategory preferenceCategoryMore) {
  398. boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled);
  399. Preference pHelp = findPreference("help");
  400. if (pHelp != null) {
  401. if (helpEnabled) {
  402. pHelp.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  403. @Override
  404. public boolean onPreferenceClick(Preference preference) {
  405. String helpWeb = getString(R.string.url_help);
  406. if (helpWeb != null && helpWeb.length() > 0) {
  407. Uri uriUrl = Uri.parse(helpWeb);
  408. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  409. startActivity(intent);
  410. }
  411. return true;
  412. }
  413. });
  414. } else {
  415. preferenceCategoryMore.removePreference(pHelp);
  416. }
  417. }
  418. }
  419. private void setupContactsBackupPreference(PreferenceCategory preferenceCategoryMore) {
  420. boolean contactsBackupEnabled = !getResources().getBoolean(R.bool.show_drawer_contacts_backup)
  421. && getResources().getBoolean(R.bool.contacts_backup);
  422. Preference pContactsBackup = findPreference("contacts");
  423. if (pContactsBackup != null) {
  424. if (contactsBackupEnabled) {
  425. pContactsBackup.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  426. @Override
  427. public boolean onPreferenceClick(Preference preference) {
  428. Intent contactsIntent = new Intent(getApplicationContext(), ContactsPreferenceActivity.class);
  429. contactsIntent.putExtra(ContactsPreferenceActivity.EXTRA_SHOW_SIDEBAR, false);
  430. startActivity(contactsIntent);
  431. return true;
  432. }
  433. });
  434. } else {
  435. preferenceCategoryMore.removePreference(pContactsBackup);
  436. }
  437. }
  438. }
  439. private void setupCalendarPreference(PreferenceCategory preferenceCategoryMore) {
  440. boolean calendarContactsEnabled = getResources().getBoolean(R.bool.davdroid_integration_enabled);
  441. Preference pCalendarContacts = findPreference("calendar_contacts");
  442. if (pCalendarContacts != null) {
  443. if (calendarContactsEnabled) {
  444. final Activity activity = this;
  445. pCalendarContacts.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  446. @Override
  447. public boolean onPreferenceClick(Preference preference) {
  448. try {
  449. launchDavDroidLogin();
  450. } catch (Throwable t) {
  451. Log_OC.e(TAG, "Base Uri for account could not be resolved to call DAVdroid!", t);
  452. DisplayUtils.showSnackMessage(
  453. activity,
  454. R.string.prefs_calendar_contacts_address_resolve_error
  455. );
  456. }
  457. return true;
  458. }
  459. });
  460. } else {
  461. preferenceCategoryMore.removePreference(pCalendarContacts);
  462. }
  463. }
  464. }
  465. private void setupDetailsCategory(int accentColor, PreferenceScreen preferenceScreen) {
  466. PreferenceCategory preferenceCategoryDetails = (PreferenceCategory) findPreference("details");
  467. preferenceCategoryDetails.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_category_details),
  468. accentColor));
  469. boolean fPassCodeEnabled = getResources().getBoolean(R.bool.passcode_enabled);
  470. boolean fPrintEnabled = getResources().getBoolean(R.bool.fingerprint_enabled);
  471. boolean fShowHiddenFilesEnabled = getResources().getBoolean(R.bool.show_hidden_files_enabled);
  472. setupPasscodePreference(preferenceCategoryDetails, fPassCodeEnabled);
  473. setupFingerprintPreference(preferenceCategoryDetails, fPrintEnabled);
  474. setupHiddenFilesPreference(preferenceCategoryDetails, fShowHiddenFilesEnabled);
  475. setupExpertModePreference(preferenceCategoryDetails);
  476. if (!fShowHiddenFilesEnabled && !fPrintEnabled && !fPassCodeEnabled) {
  477. preferenceScreen.removePreference(preferenceCategoryDetails);
  478. }
  479. }
  480. private void setupExpertModePreference(PreferenceCategory preferenceCategoryDetails) {
  481. mExpertMode = (SwitchPreference) findPreference(PREFERENCE_EXPERT_MODE);
  482. if (getResources().getBoolean(R.bool.syncedFolder_light)) {
  483. preferenceCategoryDetails.removePreference(mExpertMode);
  484. } else {
  485. mExpertMode = (SwitchPreference) findPreference(PREFERENCE_EXPERT_MODE);
  486. mExpertMode.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  487. @Override
  488. public boolean onPreferenceClick(Preference preference) {
  489. SharedPreferences appPrefs =
  490. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  491. SharedPreferences.Editor editor = appPrefs.edit();
  492. editor.putBoolean(PREFERENCE_EXPERT_MODE, mExpertMode.isChecked());
  493. editor.apply();
  494. if (mExpertMode.isChecked()) {
  495. Log_OC.startLogging(getApplicationContext());
  496. } else {
  497. if (!BuildConfig.DEBUG &&
  498. !getApplicationContext().getResources().getBoolean(R.bool.logger_enabled)) {
  499. Log_OC.stopLogging();
  500. }
  501. }
  502. return true;
  503. }
  504. });
  505. }
  506. }
  507. private void setupHiddenFilesPreference(PreferenceCategory preferenceCategoryDetails,
  508. boolean fShowHiddenFilesEnabled) {
  509. mShowHiddenFiles = (SwitchPreference) findPreference("show_hidden_files");
  510. if (fShowHiddenFilesEnabled) {
  511. mShowHiddenFiles.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  512. @Override
  513. public boolean onPreferenceClick(Preference preference) {
  514. SharedPreferences appPrefs =
  515. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  516. SharedPreferences.Editor editor = appPrefs.edit();
  517. editor.putBoolean("show_hidden_files_pref", mShowHiddenFiles.isChecked());
  518. editor.apply();
  519. return true;
  520. }
  521. });
  522. } else {
  523. preferenceCategoryDetails.removePreference(mShowHiddenFiles);
  524. }
  525. }
  526. private void setupFingerprintPreference(PreferenceCategory preferenceCategoryDetails, boolean fPrintEnabled) {
  527. fPrint = (SwitchPreference) findPreference(PREFERENCE_USE_FINGERPRINT);
  528. if (fPrint != null) {
  529. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  530. if (FingerprintActivity.isFingerprintCapable(MainApp.getAppContext()) && fPrintEnabled) {
  531. final Activity activity = this;
  532. fPrint.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
  533. @Override
  534. public boolean onPreferenceChange(Preference preference, Object newValue) {
  535. Boolean incoming = (Boolean) newValue;
  536. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  537. if (FingerprintActivity.isFingerprintReady(MainApp.getAppContext())) {
  538. SharedPreferences appPrefs =
  539. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  540. SharedPreferences.Editor editor = appPrefs.edit();
  541. editor.putBoolean(PREFERENCE_USE_FINGERPRINT, incoming);
  542. editor.apply();
  543. return true;
  544. } else {
  545. if (incoming) {
  546. DisplayUtils.showSnackMessage(activity, R.string.prefs_fingerprint_notsetup);
  547. fPrint.setChecked(false);
  548. }
  549. SharedPreferences appPrefs =
  550. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  551. SharedPreferences.Editor editor = appPrefs.edit();
  552. editor.putBoolean(PREFERENCE_USE_FINGERPRINT, false);
  553. editor.apply();
  554. return false;
  555. }
  556. } else {
  557. return false;
  558. }
  559. }
  560. });
  561. if (!FingerprintActivity.isFingerprintReady(MainApp.getAppContext())) {
  562. fPrint.setChecked(false);
  563. }
  564. } else {
  565. preferenceCategoryDetails.removePreference(fPrint);
  566. }
  567. } else {
  568. preferenceCategoryDetails.removePreference(fPrint);
  569. }
  570. }
  571. }
  572. private void setupPasscodePreference(PreferenceCategory preferenceCategoryDetails, boolean fPassCodeEnabled) {
  573. pCode = (SwitchPreference) findPreference(PassCodeActivity.PREFERENCE_SET_PASSCODE);
  574. if (pCode != null && fPassCodeEnabled) {
  575. pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
  576. @Override
  577. public boolean onPreferenceChange(Preference preference, Object newValue) {
  578. Intent i = new Intent(getApplicationContext(), PassCodeActivity.class);
  579. Boolean incoming = (Boolean) newValue;
  580. i.setAction(
  581. incoming ? PassCodeActivity.ACTION_REQUEST_WITH_RESULT :
  582. PassCodeActivity.ACTION_CHECK_WITH_RESULT
  583. );
  584. startActivityForResult(i, incoming ? ACTION_REQUEST_PASSCODE :
  585. ACTION_CONFIRM_PASSCODE);
  586. // Don't update just yet, we will decide on it in onActivityResult
  587. return false;
  588. }
  589. });
  590. } else {
  591. preferenceCategoryDetails.removePreference(pCode);
  592. }
  593. }
  594. private void setupAutoUploadCategory(int accentColor, PreferenceScreen preferenceScreen) {
  595. PreferenceCategory preferenceCategorySyncedFolders =
  596. (PreferenceCategory) findPreference("synced_folders_category");
  597. preferenceCategorySyncedFolders.setTitle(ThemeUtils.getColoredTitle(getString(R.string.drawer_synced_folders),
  598. accentColor));
  599. if (!getResources().getBoolean(R.bool.syncedFolder_light)) {
  600. preferenceScreen.removePreference(preferenceCategorySyncedFolders);
  601. } else {
  602. // Upload on WiFi
  603. final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
  604. final Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
  605. final SwitchPreference pUploadOnWifiCheckbox = (SwitchPreference) findPreference("synced_folder_on_wifi");
  606. pUploadOnWifiCheckbox.setChecked(
  607. arbitraryDataProvider.getBooleanValue(account, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI));
  608. pUploadOnWifiCheckbox.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  609. @Override
  610. public boolean onPreferenceClick(Preference preference) {
  611. arbitraryDataProvider.storeOrUpdateKeyValue(account.name, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI,
  612. String.valueOf(pUploadOnWifiCheckbox.isChecked()));
  613. return true;
  614. }
  615. });
  616. Preference pSyncedFolder = findPreference("synced_folders_configure_folders");
  617. if (pSyncedFolder != null) {
  618. if (getResources().getBoolean(R.bool.syncedFolder_light)
  619. && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  620. pSyncedFolder.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  621. @Override
  622. public boolean onPreferenceClick(Preference preference) {
  623. Intent syncedFoldersIntent =
  624. new Intent(getApplicationContext(), SyncedFoldersActivity.class);
  625. syncedFoldersIntent.putExtra(SyncedFoldersActivity.EXTRA_SHOW_SIDEBAR, false);
  626. startActivity(syncedFoldersIntent);
  627. return true;
  628. }
  629. });
  630. } else {
  631. preferenceCategorySyncedFolders.removePreference(pSyncedFolder);
  632. }
  633. }
  634. }
  635. }
  636. private void setupGeneralCategory(int accentColor) {
  637. PreferenceCategory preferenceCategoryGeneral = (PreferenceCategory) findPreference("general");
  638. preferenceCategoryGeneral.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_category_general),
  639. accentColor));
  640. mPrefStoragePath = (ListPreference) findPreference(PreferenceKeys.STORAGE_PATH);
  641. if (mPrefStoragePath != null) {
  642. StoragePoint[] storageOptions = DataStorageProvider.getInstance().getAvailableStoragePoints();
  643. String[] entries = new String[storageOptions.length];
  644. String[] values = new String[storageOptions.length];
  645. for (int i = 0; i < storageOptions.length; ++i) {
  646. entries[i] = storageOptions[i].getDescription();
  647. values[i] = storageOptions[i].getPath();
  648. }
  649. mPrefStoragePath.setEntries(entries);
  650. mPrefStoragePath.setEntryValues(values);
  651. mPrefStoragePath.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
  652. @Override
  653. public boolean onPreferenceChange(Preference preference, Object newValue) {
  654. String newPath = (String) newValue;
  655. if (mStoragePath.equals(newPath)) {
  656. return true;
  657. }
  658. StorageMigration storageMigration = new StorageMigration(Preferences.this, mStoragePath, newPath);
  659. storageMigration.setStorageMigrationProgressListener(Preferences.this);
  660. storageMigration.migrate();
  661. return false;
  662. }
  663. });
  664. }
  665. loadStoragePath();
  666. }
  667. private String getAppVersion() {
  668. String temp;
  669. try {
  670. PackageInfo pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
  671. temp = pkg.versionName;
  672. } catch (NameNotFoundException e) {
  673. temp = "";
  674. Log_OC.e(TAG, "Error while showing about dialog", e);
  675. }
  676. return temp;
  677. }
  678. private void setupActionBar() {
  679. ActionBar actionBar = getDelegate().getSupportActionBar();
  680. actionBar.setDisplayHomeAsUpEnabled(true);
  681. ThemeUtils.setColoredTitle(actionBar, getString(R.string.actionbar_settings));
  682. actionBar.setBackgroundDrawable(new ColorDrawable(ThemeUtils.primaryColor()));
  683. getWindow().getDecorView().setBackgroundDrawable(new ColorDrawable(ResourcesCompat
  684. .getColor(getResources(), R.color.background_color, null)));
  685. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  686. getWindow().setStatusBarColor(ThemeUtils.primaryDarkColor());
  687. }
  688. Drawable backArrow = getResources().getDrawable(R.drawable.ic_arrow_back);
  689. actionBar.setHomeAsUpIndicator(ThemeUtils.tintDrawable(backArrow, ThemeUtils.fontColor()));
  690. // For adding content description tag to a title field in the action bar
  691. int actionBarTitleId = getResources().getIdentifier("action_bar_title", "id", "android");
  692. View actionBarTitleView = getWindow().getDecorView().findViewById(actionBarTitleId);
  693. if (actionBarTitleView != null) { // it's null in Android 2.x
  694. getWindow().getDecorView().findViewById(actionBarTitleId).
  695. setContentDescription(getString(R.string.actionbar_settings));
  696. }
  697. }
  698. private void launchDavDroidLogin()
  699. throws com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException,
  700. OperationCanceledException,
  701. AuthenticatorException,
  702. IOException {
  703. Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
  704. Intent davDroidLoginIntent = new Intent();
  705. davDroidLoginIntent.setClassName("at.bitfire.davdroid", "at.bitfire.davdroid.ui.setup.LoginActivity");
  706. if (getPackageManager().resolveActivity(davDroidLoginIntent, 0) != null) {
  707. // arguments
  708. if (mUri != null) {
  709. davDroidLoginIntent.putExtra("url", mUri.toString() + DAV_PATH);
  710. }
  711. davDroidLoginIntent.putExtra("username", AccountUtils.getAccountUsername(account.name));
  712. //loginIntent.putExtra("password", "...");
  713. startActivityForResult(davDroidLoginIntent, ACTION_REQUEST_CODE_DAVDROID_SETUP);
  714. } else {
  715. // DAVdroid not installed
  716. Intent installIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=at.bitfire.davdroid"));
  717. // launch market(s)
  718. if (installIntent.resolveActivity(getPackageManager()) != null) {
  719. startActivity(installIntent);
  720. } else {
  721. // no f-droid market app or Play store installed --> launch browser for f-droid url
  722. Intent downloadIntent = new Intent(Intent.ACTION_VIEW,
  723. Uri.parse("https://f-droid.org/repository/browse/?fdid=at.bitfire.davdroid"));
  724. startActivity(downloadIntent);
  725. DisplayUtils.showSnackMessage(this, R.string.prefs_calendar_contacts_no_store_error);
  726. }
  727. }
  728. }
  729. private void setupBaseUri() {
  730. // retrieve and set user's base URI
  731. Thread t = new Thread(new Runnable() {
  732. public void run() {
  733. try {
  734. Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
  735. OwnCloudAccount ocAccount = new OwnCloudAccount(account, MainApp.getAppContext());
  736. mUri = OwnCloudClientManagerFactory.getDefaultSingleton().
  737. getClientFor(ocAccount, getApplicationContext()).getBaseUri();
  738. } catch (Throwable t) {
  739. Log_OC.e(TAG, "Error retrieving user's base URI", t);
  740. }
  741. }
  742. });
  743. t.start();
  744. }
  745. @Override
  746. protected void onResume() {
  747. super.onResume();
  748. AnalyticsUtils.setCurrentScreenName(this, SCREEN_NAME, TAG);
  749. SharedPreferences appPrefs =
  750. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  751. boolean state = appPrefs.getBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, false);
  752. pCode.setChecked(state);
  753. }
  754. @Override
  755. public boolean onCreateOptionsMenu(Menu menu) {
  756. super.onCreateOptionsMenu(menu);
  757. return true;
  758. }
  759. @Override
  760. public boolean onMenuItemSelected(int featureId, MenuItem item) {
  761. super.onMenuItemSelected(featureId, item);
  762. Intent intent;
  763. switch (item.getItemId()) {
  764. case android.R.id.home:
  765. intent = new Intent(getBaseContext(), FileDisplayActivity.class);
  766. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  767. startActivity(intent);
  768. break;
  769. default:
  770. Log_OC.w(TAG, "Unknown menu item triggered");
  771. return false;
  772. }
  773. return true;
  774. }
  775. @Override
  776. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  777. super.onActivityResult(requestCode, resultCode, data);
  778. if (requestCode == ACTION_REQUEST_PASSCODE && resultCode == RESULT_OK) {
  779. String passcode = data.getStringExtra(PassCodeActivity.KEY_PASSCODE);
  780. if (passcode != null && passcode.length() == 4) {
  781. SharedPreferences.Editor appPrefs = PreferenceManager
  782. .getDefaultSharedPreferences(getApplicationContext()).edit();
  783. for (int i = 1; i <= 4; ++i) {
  784. appPrefs.putString(PassCodeActivity.PREFERENCE_PASSCODE_D + i, passcode.substring(i - 1, i));
  785. }
  786. appPrefs.putBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, true);
  787. appPrefs.apply();
  788. DisplayUtils.showSnackMessage(this, R.string.pass_code_stored);
  789. }
  790. } else if (requestCode == ACTION_CONFIRM_PASSCODE && resultCode == RESULT_OK) {
  791. if (data.getBooleanExtra(PassCodeActivity.KEY_CHECK_RESULT, false)) {
  792. SharedPreferences.Editor appPrefs = PreferenceManager
  793. .getDefaultSharedPreferences(getApplicationContext()).edit();
  794. appPrefs.putBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, false);
  795. appPrefs.apply();
  796. DisplayUtils.showSnackMessage(this, R.string.pass_code_removed);
  797. }
  798. } else if (requestCode == ACTION_REQUEST_CODE_DAVDROID_SETUP && resultCode == RESULT_OK) {
  799. DisplayUtils.showSnackMessage(this, R.string.prefs_calendar_contacts_sync_setup_successful);
  800. }
  801. }
  802. @Override
  803. public MenuInflater getMenuInflater() {
  804. return getDelegate().getMenuInflater();
  805. }
  806. @Override
  807. public void setContentView(@LayoutRes int layoutResID) {
  808. getDelegate().setContentView(layoutResID);
  809. }
  810. @Override
  811. public void setContentView(View view) {
  812. getDelegate().setContentView(view);
  813. }
  814. @Override
  815. public void setContentView(View view, ViewGroup.LayoutParams params) {
  816. getDelegate().setContentView(view, params);
  817. }
  818. @Override
  819. public void addContentView(View view, ViewGroup.LayoutParams params) {
  820. getDelegate().addContentView(view, params);
  821. }
  822. @Override
  823. protected void onPostResume() {
  824. super.onPostResume();
  825. getDelegate().onPostResume();
  826. }
  827. @Override
  828. protected void onTitleChanged(CharSequence title, int color) {
  829. super.onTitleChanged(title, color);
  830. getDelegate().setTitle(title);
  831. }
  832. @Override
  833. public void onConfigurationChanged(Configuration newConfig) {
  834. super.onConfigurationChanged(newConfig);
  835. getDelegate().onConfigurationChanged(newConfig);
  836. }
  837. @Override
  838. protected void onPostCreate(Bundle savedInstanceState) {
  839. super.onPostCreate(savedInstanceState);
  840. getDelegate().onPostCreate(savedInstanceState);
  841. }
  842. @Override
  843. protected void onDestroy() {
  844. super.onDestroy();
  845. getDelegate().onDestroy();
  846. }
  847. @Override
  848. protected void onStop() {
  849. super.onStop();
  850. getDelegate().onStop();
  851. }
  852. public void invalidateOptionsMenu() {
  853. getDelegate().invalidateOptionsMenu();
  854. }
  855. private AppCompatDelegate getDelegate() {
  856. if (mDelegate == null) {
  857. mDelegate = AppCompatDelegate.create(this, null);
  858. }
  859. return mDelegate;
  860. }
  861. private void loadExternalSettingLinks(PreferenceCategory preferenceCategory) {
  862. if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  863. ExternalLinksProvider externalLinksProvider = new ExternalLinksProvider(getContentResolver());
  864. for (final ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.SETTINGS)) {
  865. // only add if it does not exist, in case activity is re-used
  866. if (findPreference(link.id.toString()) == null) {
  867. Preference p = new Preference(this);
  868. p.setTitle(link.name);
  869. p.setKey(link.id.toString());
  870. p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  871. @Override
  872. public boolean onPreferenceClick(Preference preference) {
  873. Intent externalWebViewIntent =
  874. new Intent(getApplicationContext(), ExternalSiteWebView.class);
  875. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, link.name);
  876. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, link.url);
  877. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
  878. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, link.id);
  879. startActivity(externalWebViewIntent);
  880. return true;
  881. }
  882. });
  883. preferenceCategory.addPreference(p);
  884. }
  885. }
  886. }
  887. }
  888. /**
  889. * Save storage path
  890. */
  891. private void saveStoragePath(String newStoragePath) {
  892. SharedPreferences appPrefs =
  893. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  894. mStoragePath = newStoragePath;
  895. MainApp.setStoragePath(mStoragePath);
  896. SharedPreferences.Editor editor = appPrefs.edit();
  897. editor.putString(PreferenceKeys.STORAGE_PATH, mStoragePath);
  898. editor.apply();
  899. String storageDescription = DataStorageProvider.getInstance().getStorageDescriptionByPath(mStoragePath);
  900. mPrefStoragePath.setSummary(storageDescription);
  901. mPrefStoragePath.setValue(newStoragePath);
  902. }
  903. /**
  904. * Load storage path set on preferences
  905. */
  906. private void loadStoragePath() {
  907. SharedPreferences appPrefs =
  908. PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  909. mStoragePath = appPrefs.getString(PreferenceKeys.STORAGE_PATH, Environment.getExternalStorageDirectory()
  910. .getAbsolutePath());
  911. String storageDescription = DataStorageProvider.getInstance().getStorageDescriptionByPath(mStoragePath);
  912. mPrefStoragePath.setSummary(storageDescription);
  913. }
  914. @Override
  915. public void onStorageMigrationFinished(String storagePath, boolean succeed) {
  916. if (succeed) {
  917. saveStoragePath(storagePath);
  918. }
  919. }
  920. @Override
  921. public void onCancelMigration() {
  922. // Migration was canceled so we don't do anything
  923. }
  924. /**
  925. *
  926. * Class for loading the version number
  927. *
  928. */
  929. private class LoadingVersionNumberTask extends AsyncTask<Void, Void, Integer> {
  930. protected Integer doInBackground(Void... args) {
  931. try {
  932. URL url = new URL(getString(R.string.dev_latest));
  933. BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
  934. Integer latestVersion = Integer.parseInt(in.readLine());
  935. in.close();
  936. return latestVersion;
  937. } catch (IOException e) {
  938. Log_OC.e(TAG, "Error loading version number", e);
  939. }
  940. return -1;
  941. }
  942. }
  943. }