DrawerActivity.java 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * @author Andy Scherzinger
  5. * @author Tobias Kaminsky
  6. * @author Chris Narkiewicz <hello@ezaquarii.com>
  7. * @author TSI-mc
  8. * Copyright (C) 2016 Andy Scherzinger
  9. * Copyright (C) 2017 Tobias Kaminsky
  10. * Copyright (C) 2016 Nextcloud
  11. * Copyright (C) 2016 ownCloud Inc.
  12. * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  13. * Copyright (C) 2020 Infomaniak Network SA
  14. * Copyright (C) 2021 TSI-mc
  15. *
  16. * This program is free software; you can redistribute it and/or
  17. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  18. * License as published by the Free Software Foundation; either
  19. * version 3 of the License, or any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public
  27. * License along with this program. If not, see <http://www.gnu.org/licenses/>.
  28. */
  29. package com.owncloud.android.ui.activity;
  30. import android.accounts.AuthenticatorException;
  31. import android.accounts.OperationCanceledException;
  32. import android.app.Activity;
  33. import android.content.Context;
  34. import android.content.Intent;
  35. import android.content.res.Configuration;
  36. import android.graphics.Bitmap;
  37. import android.graphics.drawable.BitmapDrawable;
  38. import android.graphics.drawable.ColorDrawable;
  39. import android.graphics.drawable.Drawable;
  40. import android.graphics.drawable.LayerDrawable;
  41. import android.net.Uri;
  42. import android.os.Bundle;
  43. import android.os.Handler;
  44. import android.os.SystemClock;
  45. import android.text.TextUtils;
  46. import android.view.Menu;
  47. import android.view.MenuItem;
  48. import android.view.View;
  49. import android.view.ViewGroup.LayoutParams;
  50. import android.view.ViewGroup.MarginLayoutParams;
  51. import android.webkit.URLUtil;
  52. import android.widget.FrameLayout;
  53. import android.widget.ImageView;
  54. import android.widget.LinearLayout;
  55. import android.widget.ProgressBar;
  56. import android.widget.TextView;
  57. import com.bumptech.glide.GenericRequestBuilder;
  58. import com.bumptech.glide.Glide;
  59. import com.bumptech.glide.load.engine.DiskCacheStrategy;
  60. import com.bumptech.glide.load.model.StreamEncoder;
  61. import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
  62. import com.bumptech.glide.request.animation.GlideAnimation;
  63. import com.bumptech.glide.request.target.SimpleTarget;
  64. import com.google.android.material.button.MaterialButton;
  65. import com.google.android.material.navigation.NavigationView;
  66. import com.nextcloud.client.account.User;
  67. import com.nextcloud.client.di.Injectable;
  68. import com.nextcloud.client.network.ClientFactory;
  69. import com.nextcloud.client.onboarding.FirstRunActivity;
  70. import com.nextcloud.client.preferences.AppPreferences;
  71. import com.nextcloud.common.NextcloudClient;
  72. import com.nextcloud.java.util.Optional;
  73. import com.nextcloud.ui.ChooseAccountDialogFragment;
  74. import com.owncloud.android.MainApp;
  75. import com.owncloud.android.R;
  76. import com.owncloud.android.authentication.PassCodeManager;
  77. import com.owncloud.android.datamodel.ArbitraryDataProvider;
  78. import com.owncloud.android.datamodel.ExternalLinksProvider;
  79. import com.owncloud.android.datamodel.FileDataStorageManager;
  80. import com.owncloud.android.datamodel.OCFile;
  81. import com.owncloud.android.lib.common.ExternalLink;
  82. import com.owncloud.android.lib.common.ExternalLinkType;
  83. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  84. import com.owncloud.android.lib.common.Quota;
  85. import com.owncloud.android.lib.common.UserInfo;
  86. import com.owncloud.android.lib.common.accounts.ExternalLinksOperation;
  87. import com.owncloud.android.lib.common.operations.RemoteOperation;
  88. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  89. import com.owncloud.android.lib.common.utils.Log_OC;
  90. import com.owncloud.android.lib.resources.files.SearchRemoteOperation;
  91. import com.owncloud.android.lib.resources.status.OCCapability;
  92. import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
  93. import com.owncloud.android.operations.GetCapabilitiesOperation;
  94. import com.owncloud.android.ui.activities.ActivitiesActivity;
  95. import com.owncloud.android.ui.events.AccountRemovedEvent;
  96. import com.owncloud.android.ui.events.ChangeMenuEvent;
  97. import com.owncloud.android.ui.events.DummyDrawerEvent;
  98. import com.owncloud.android.ui.events.SearchEvent;
  99. import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment;
  100. import com.owncloud.android.ui.fragment.GalleryFragment;
  101. import com.owncloud.android.ui.fragment.OCFileListFragment;
  102. import com.owncloud.android.ui.trashbin.TrashbinActivity;
  103. import com.owncloud.android.utils.BitmapUtils;
  104. import com.owncloud.android.utils.DisplayUtils;
  105. import com.owncloud.android.utils.DrawerMenuUtil;
  106. import com.owncloud.android.utils.FilesSyncHelper;
  107. import com.owncloud.android.utils.svg.MenuSimpleTarget;
  108. import com.owncloud.android.utils.svg.SVGorImage;
  109. import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder;
  110. import com.owncloud.android.utils.svg.SvgOrImageDecoder;
  111. import com.owncloud.android.utils.theme.ThemeBarUtils;
  112. import com.owncloud.android.utils.theme.ThemeColorUtils;
  113. import com.owncloud.android.utils.theme.ThemeDrawableUtils;
  114. import com.owncloud.android.utils.theme.ThemeMenuUtils;
  115. import org.greenrobot.eventbus.EventBus;
  116. import org.greenrobot.eventbus.Subscribe;
  117. import org.greenrobot.eventbus.ThreadMode;
  118. import java.io.IOException;
  119. import java.io.InputStream;
  120. import java.util.ArrayList;
  121. import java.util.List;
  122. import javax.inject.Inject;
  123. import androidx.annotation.NonNull;
  124. import androidx.appcompat.app.ActionBarDrawerToggle;
  125. import androidx.core.content.ContextCompat;
  126. import androidx.core.content.res.ResourcesCompat;
  127. import androidx.core.view.GravityCompat;
  128. import androidx.drawerlayout.widget.DrawerLayout;
  129. import androidx.fragment.app.Fragment;
  130. /**
  131. * Base class to handle setup of the drawer implementation including user switching and avatar fetching and fallback
  132. * generation.
  133. */
  134. public abstract class DrawerActivity extends ToolbarActivity
  135. implements DisplayUtils.AvatarGenerationListener, Injectable {
  136. private static final String TAG = DrawerActivity.class.getSimpleName();
  137. private static final String KEY_IS_ACCOUNT_CHOOSER_ACTIVE = "IS_ACCOUNT_CHOOSER_ACTIVE";
  138. private static final String KEY_CHECKED_MENU_ITEM = "CHECKED_MENU_ITEM";
  139. private static final int ACTION_MANAGE_ACCOUNTS = 101;
  140. private static final int MENU_ORDER_EXTERNAL_LINKS = 3;
  141. private static final int MENU_ITEM_EXTERNAL_LINK = 111;
  142. private static final int MAX_LOGO_SIZE_PX = 1000;
  143. /**
  144. * Reference to the drawer layout.
  145. */
  146. private DrawerLayout mDrawerLayout;
  147. /**
  148. * Reference to the drawer toggle.
  149. */
  150. protected ActionBarDrawerToggle mDrawerToggle;
  151. /**
  152. * Reference to the navigation view.
  153. */
  154. private NavigationView mNavigationView;
  155. /**
  156. * Reference to the navigation view header.
  157. */
  158. private View mNavigationViewHeader;
  159. /**
  160. * Flag to signal if the account chooser is active.
  161. */
  162. private boolean mIsAccountChooserActive;
  163. /**
  164. * Id of the checked menu item.
  165. */
  166. private int mCheckedMenuItem = Menu.NONE;
  167. /**
  168. * container layout of the quota view.
  169. */
  170. private LinearLayout mQuotaView;
  171. /**
  172. * progress bar of the quota view.
  173. */
  174. private ProgressBar mQuotaProgressBar;
  175. /**
  176. * text view of the quota view.
  177. */
  178. private TextView mQuotaTextPercentage;
  179. private TextView mQuotaTextLink;
  180. /**
  181. * runnable that will be executed after the drawer has been closed.
  182. */
  183. private Runnable pendingRunnable;
  184. private ExternalLinksProvider externalLinksProvider;
  185. private ArbitraryDataProvider arbitraryDataProvider;
  186. @Inject
  187. AppPreferences preferences;
  188. @Inject
  189. ClientFactory clientFactory;
  190. /**
  191. * Initializes the drawer, its content and highlights the menu item with the given id. This method needs to be
  192. * called after the content view has been set.
  193. *
  194. * @param menuItemId the menu item to be checked/highlighted
  195. */
  196. protected void setupDrawer(int menuItemId) {
  197. setupDrawer();
  198. setDrawerMenuItemChecked(menuItemId);
  199. }
  200. /**
  201. * Initializes the drawer and its content. This method needs to be called after the content view has been set.
  202. */
  203. protected void setupDrawer() {
  204. mDrawerLayout = findViewById(R.id.drawer_layout);
  205. mNavigationView = findViewById(R.id.nav_view);
  206. if (mNavigationView != null) {
  207. // Setting up drawer header
  208. mNavigationViewHeader = mNavigationView.getHeaderView(0);
  209. updateHeader();
  210. setupDrawerMenu(mNavigationView);
  211. getAndDisplayUserQuota();
  212. setupQuotaElement();
  213. }
  214. setupDrawerToggle();
  215. if (getSupportActionBar() != null) {
  216. getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  217. }
  218. }
  219. /**
  220. * initializes and sets up the drawer toggle.
  221. */
  222. private void setupDrawerToggle() {
  223. mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
  224. /** Called when a drawer has settled in a completely closed state. */
  225. public void onDrawerClosed(View view) {
  226. super.onDrawerClosed(view);
  227. supportInvalidateOptionsMenu();
  228. mDrawerToggle.setDrawerIndicatorEnabled(isDrawerIndicatorAvailable());
  229. if (pendingRunnable != null) {
  230. new Handler().post(pendingRunnable);
  231. pendingRunnable = null;
  232. }
  233. closeDrawer();
  234. }
  235. /** Called when a drawer has settled in a completely open state. */
  236. public void onDrawerOpened(View drawerView) {
  237. super.onDrawerOpened(drawerView);
  238. mDrawerToggle.setDrawerIndicatorEnabled(true);
  239. supportInvalidateOptionsMenu();
  240. }
  241. };
  242. // Set the drawer toggle as the DrawerListener
  243. mDrawerLayout.addDrawerListener(mDrawerToggle);
  244. mDrawerToggle.setDrawerIndicatorEnabled(true);
  245. mDrawerToggle.setDrawerSlideAnimationEnabled(true);
  246. Drawable backArrow = ResourcesCompat.getDrawable(getResources(),
  247. R.drawable.ic_arrow_back,
  248. null);
  249. mDrawerToggle.setHomeAsUpIndicator(
  250. ThemeDrawableUtils.tintDrawable(backArrow, ThemeColorUtils.appBarPrimaryFontColor(this)));
  251. mDrawerToggle.getDrawerArrowDrawable().setColor(ThemeColorUtils.appBarPrimaryFontColor(this));
  252. }
  253. /**
  254. * setup quota elements of the drawer.
  255. */
  256. private void setupQuotaElement() {
  257. mQuotaView = (LinearLayout) findQuotaViewById(R.id.drawer_quota);
  258. mQuotaProgressBar = (ProgressBar) findQuotaViewById(R.id.drawer_quota_ProgressBar);
  259. mQuotaTextPercentage = (TextView) findQuotaViewById(R.id.drawer_quota_percentage);
  260. mQuotaTextLink = (TextView) findQuotaViewById(R.id.drawer_quota_link);
  261. ThemeBarUtils.colorProgressBar(mQuotaProgressBar, ThemeColorUtils.primaryColor(this));
  262. }
  263. public void updateHeader() {
  264. if (getAccount() != null &&
  265. getStorageManager().getCapability(getAccount().name).getServerBackground() != null) {
  266. OCCapability capability = getStorageManager().getCapability(getAccount().name);
  267. String logo = capability.getServerLogo();
  268. int primaryColor = ThemeColorUtils.primaryColor(getAccount(), false, this);
  269. // set background to primary color
  270. LinearLayout drawerHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_view);
  271. drawerHeader.setBackgroundColor(ThemeColorUtils.unchangedPrimaryColor(getAccount(), this));
  272. if (!TextUtils.isEmpty(logo) && URLUtil.isValidUrl(logo)) {
  273. // background image
  274. GenericRequestBuilder<Uri, InputStream, SVGorImage, Bitmap> requestBuilder = Glide.with(this)
  275. .using(Glide.buildStreamModelLoader(Uri.class, this), InputStream.class)
  276. .from(Uri.class)
  277. .as(SVGorImage.class)
  278. .transcode(new SvgOrImageBitmapTranscoder(128, 128), Bitmap.class)
  279. .sourceEncoder(new StreamEncoder())
  280. .cacheDecoder(new FileToStreamDecoder<>(new SvgOrImageDecoder()))
  281. .decoder(new SvgOrImageDecoder());
  282. // background image
  283. SimpleTarget target = new SimpleTarget<Bitmap>() {
  284. @Override
  285. public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
  286. Bitmap logo = resource;
  287. int width = resource.getWidth();
  288. int height = resource.getHeight();
  289. int max = Math.max(width, height);
  290. if (max > MAX_LOGO_SIZE_PX) {
  291. logo = BitmapUtils.scaleBitmap(resource, MAX_LOGO_SIZE_PX, width, height, max);
  292. }
  293. Drawable[] drawables = {new ColorDrawable(primaryColor), new BitmapDrawable(logo)};
  294. LayerDrawable layerDrawable = new LayerDrawable(drawables);
  295. String name = capability.getServerName();
  296. setDrawerHeaderLogo(layerDrawable, name);
  297. }
  298. };
  299. requestBuilder
  300. .diskCacheStrategy(DiskCacheStrategy.SOURCE)
  301. .load(Uri.parse(logo))
  302. .into(target);
  303. }
  304. }
  305. }
  306. private void setDrawerHeaderLogo(Drawable drawable, String name) {
  307. ImageView imageHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_logo);
  308. imageHeader.setImageDrawable(drawable);
  309. imageHeader.setScaleType(ImageView.ScaleType.FIT_START);
  310. imageHeader.setAdjustViewBounds(true);
  311. imageHeader.setMaxWidth(DisplayUtils.convertDpToPixel(100f, this));
  312. MarginLayoutParams oldParam = (MarginLayoutParams) imageHeader.getLayoutParams();
  313. MarginLayoutParams params = new MarginLayoutParams(LayoutParams.WRAP_CONTENT,
  314. LayoutParams.MATCH_PARENT);
  315. params.leftMargin = oldParam.leftMargin;
  316. params.rightMargin = oldParam.rightMargin;
  317. imageHeader.setLayoutParams(new LinearLayout.LayoutParams(params));
  318. if (!TextUtils.isEmpty(name)) {
  319. TextView serverName = mNavigationViewHeader.findViewById(R.id.drawer_header_server_name);
  320. serverName.setText(name);
  321. serverName.setTextColor(ThemeColorUtils.unchangedFontColor(this));
  322. }
  323. }
  324. /**
  325. * setup drawer header, basically the logo color
  326. */
  327. private void setupDrawerHeader(FrameLayout drawerHeader) {
  328. drawerHeader.setBackgroundColor(ThemeColorUtils.primaryColor(getAccount(), true, this));
  329. }
  330. /**
  331. * setup drawer content, basically setting the item selected listener.
  332. *
  333. * @param navigationView the drawers navigation view
  334. */
  335. private void setupDrawerMenu(NavigationView navigationView) {
  336. navigationView.setItemIconTintList(null);
  337. // setup actions for drawer menu items
  338. navigationView.setNavigationItemSelectedListener(
  339. menuItem -> {
  340. mDrawerLayout.closeDrawers();
  341. // pending runnable will be executed after the drawer has been closed
  342. pendingRunnable = () -> onNavigationItemClicked(menuItem);
  343. return true;
  344. });
  345. User account = accountManager.getUser();
  346. filterDrawerMenu(navigationView.getMenu(), account);
  347. }
  348. private void filterDrawerMenu(final Menu menu, @NonNull final User user) {
  349. FileDataStorageManager storageManager = new FileDataStorageManager(user,
  350. getContentResolver());
  351. OCCapability capability = storageManager.getCapability(user.getAccountName());
  352. DrawerMenuUtil.filterSearchMenuItems(menu, user, getResources());
  353. DrawerMenuUtil.filterTrashbinMenuItem(menu, capability);
  354. DrawerMenuUtil.filterActivityMenuItem(menu, capability);
  355. DrawerMenuUtil.setupHomeMenuItem(menu, getResources());
  356. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_community,
  357. !getResources().getBoolean(R.bool.participate_enabled));
  358. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_shared, !getResources().getBoolean(R.bool.shared_enabled));
  359. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout));
  360. }
  361. @Subscribe(threadMode = ThreadMode.MAIN)
  362. public void onMessageEvent(DummyDrawerEvent event) {
  363. unsetAllDrawerMenuItems();
  364. }
  365. private void onNavigationItemClicked(final MenuItem menuItem) {
  366. setDrawerMenuItemChecked(menuItem.getItemId());
  367. int itemId = menuItem.getItemId();
  368. if (itemId == R.id.nav_all_files) {
  369. throw new RuntimeException(new RuntimeException((new RuntimeException(new RuntimeException()))));
  370. // if (this instanceof FileDisplayActivity &&
  371. // !(((FileDisplayActivity) this).getLeftFragment() instanceof GalleryFragment) &&
  372. // !(((FileDisplayActivity) this).getLeftFragment() instanceof PreviewTextStringFragment)) {
  373. // showFiles(false);
  374. // ((FileDisplayActivity) this).browseToRoot();
  375. // EventBus.getDefault().post(new ChangeMenuEvent());
  376. // } else {
  377. // Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
  378. // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  379. // intent.setAction(FileDisplayActivity.ALL_FILES);
  380. // intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItem.getItemId());
  381. // startActivity(intent);
  382. // }
  383. } else if (itemId == R.id.nav_favorites) {
  384. handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH),
  385. menuItem.getItemId());
  386. } else if (itemId == R.id.nav_gallery) {
  387. startPhotoSearch(menuItem);
  388. } else if (itemId == R.id.nav_on_device) {
  389. EventBus.getDefault().post(new ChangeMenuEvent());
  390. showFiles(true);
  391. } else if (itemId == R.id.nav_uploads) {
  392. startActivity(UploadListActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
  393. } else if (itemId == R.id.nav_trashbin) {
  394. startActivity(TrashbinActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
  395. } else if (itemId == R.id.nav_activity) {
  396. startActivity(ActivitiesActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
  397. } else if (itemId == R.id.nav_notifications) {
  398. startActivity(NotificationsActivity.class);
  399. } else if (itemId == R.id.nav_settings) {
  400. startActivity(SettingsActivity.class);
  401. } else if (itemId == R.id.nav_community) {
  402. startActivity(CommunityActivity.class);
  403. } else if (itemId == R.id.nav_logout) {
  404. mCheckedMenuItem = -1;
  405. menuItem.setChecked(false);
  406. final Optional<User> optionalUser = getUser();
  407. if (optionalUser.isPresent()) {
  408. UserInfoActivity.openAccountRemovalConfirmationDialog(optionalUser.get(), getSupportFragmentManager());
  409. }
  410. } else if (itemId == R.id.nav_shared) {
  411. handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.SHARED_FILTER),
  412. menuItem.getItemId());
  413. } else if (itemId == R.id.nav_recently_modified) {
  414. handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.RECENTLY_MODIFIED_SEARCH),
  415. menuItem.getItemId());
  416. } else {
  417. if (menuItem.getItemId() >= MENU_ITEM_EXTERNAL_LINK &&
  418. menuItem.getItemId() <= MENU_ITEM_EXTERNAL_LINK + 100) {
  419. // external link clicked
  420. externalLinkClicked(menuItem);
  421. } else {
  422. Log_OC.w(TAG, "Unknown drawer menu item clicked: " + menuItem.getTitle());
  423. }
  424. }
  425. }
  426. private void startActivity(Class<? extends Activity> activity) {
  427. startActivity(new Intent(getApplicationContext(), activity));
  428. }
  429. private void startActivity(Class<? extends Activity> activity, int flags) {
  430. Intent intent = new Intent(getApplicationContext(), activity);
  431. intent.setFlags(flags);
  432. startActivity(intent);
  433. }
  434. public void showManageAccountsDialog() {
  435. ChooseAccountDialogFragment choseAccountDialog = ChooseAccountDialogFragment.newInstance(accountManager.getUser());
  436. choseAccountDialog.show(getSupportFragmentManager(), "fragment_chose_account");
  437. }
  438. public void openManageAccounts() {
  439. Intent manageAccountsIntent = new Intent(getApplicationContext(), ManageAccountsActivity.class);
  440. startActivityForResult(manageAccountsIntent, ACTION_MANAGE_ACCOUNTS);
  441. }
  442. public void openAddAccount() {
  443. boolean isProviderOrOwnInstallationVisible = getResources()
  444. .getBoolean(R.bool.show_provider_or_own_installation);
  445. if (isProviderOrOwnInstallationVisible) {
  446. Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
  447. firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
  448. startActivity(firstRunIntent);
  449. } else {
  450. startAccountCreation();
  451. }
  452. }
  453. private void startPhotoSearch(MenuItem menuItem) {
  454. SearchEvent searchEvent = new SearchEvent("image/%", SearchRemoteOperation.SearchType.PHOTO_SEARCH);
  455. MainApp.showOnlyFilesOnDevice(false);
  456. launchActivityForSearch(searchEvent, menuItem.getItemId());
  457. }
  458. private void handleSearchEvents(SearchEvent searchEvent, int menuItemId) {
  459. if (this instanceof FileDisplayActivity) {
  460. if (((FileDisplayActivity) this).getLeftFragment() instanceof GalleryFragment) {
  461. launchActivityForSearch(searchEvent, menuItemId);
  462. } else {
  463. EventBus.getDefault().post(searchEvent);
  464. }
  465. } else {
  466. launchActivityForSearch(searchEvent, menuItemId);
  467. }
  468. }
  469. private void launchActivityForSearch(SearchEvent searchEvent, int menuItemId) {
  470. Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
  471. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  472. intent.setAction(Intent.ACTION_SEARCH);
  473. intent.putExtra(OCFileListFragment.SEARCH_EVENT, searchEvent);
  474. intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItemId);
  475. startActivity(intent);
  476. }
  477. /**
  478. * sets the new/current account and restarts. In case the given account equals the actual/current account the call
  479. * will be ignored.
  480. *
  481. * @param hashCode HashCode of account to be set
  482. */
  483. public void accountClicked(int hashCode) {
  484. final User currentUser = accountManager.getUser();
  485. if (currentUser.hashCode() != hashCode && accountManager.setCurrentOwnCloudAccount(hashCode)) {
  486. fetchExternalLinks(true);
  487. restart();
  488. }
  489. }
  490. private void externalLinkClicked(MenuItem menuItem) {
  491. for (ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.LINK)) {
  492. if (menuItem.getTitle().toString().equalsIgnoreCase(link.getName())) {
  493. if (link.getRedirect()) {
  494. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link.getUrl()));
  495. DisplayUtils.startIntentIfAppAvailable(intent, this, R.string.no_browser_available);
  496. } else {
  497. Intent externalWebViewIntent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
  498. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, link.getName());
  499. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, link.getUrl());
  500. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, true);
  501. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, menuItem.getItemId());
  502. startActivity(externalWebViewIntent);
  503. }
  504. }
  505. }
  506. }
  507. /**
  508. * checks if the drawer exists and is opened.
  509. *
  510. * @return <code>true</code> if the drawer is open, else <code>false</code>
  511. */
  512. public boolean isDrawerOpen() {
  513. return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START);
  514. }
  515. /**
  516. * closes the drawer.
  517. */
  518. public void closeDrawer() {
  519. if (mDrawerLayout != null) {
  520. mDrawerLayout.closeDrawer(GravityCompat.START);
  521. }
  522. }
  523. /**
  524. * opens the drawer.
  525. */
  526. public void openDrawer() {
  527. if (mDrawerLayout != null) {
  528. mDrawerLayout.openDrawer(GravityCompat.START);
  529. updateExternalLinksInDrawer();
  530. updateQuotaLink();
  531. }
  532. }
  533. /**
  534. * Enable or disable interaction with all drawers.
  535. *
  536. * @param lockMode The new lock mode for the given drawer. One of {@link DrawerLayout#LOCK_MODE_UNLOCKED}, {@link
  537. * DrawerLayout#LOCK_MODE_LOCKED_CLOSED} or {@link DrawerLayout#LOCK_MODE_LOCKED_OPEN}.
  538. */
  539. public void setDrawerLockMode(int lockMode) {
  540. if (mDrawerLayout != null) {
  541. mDrawerLayout.setDrawerLockMode(lockMode);
  542. }
  543. }
  544. /**
  545. * Enable or disable the drawer indicator.
  546. *
  547. * @param enable true to enable, false to disable
  548. */
  549. public void setDrawerIndicatorEnabled(boolean enable) {
  550. if (mDrawerToggle != null) {
  551. mDrawerToggle.setDrawerIndicatorEnabled(enable);
  552. }
  553. }
  554. /**
  555. * Updates title bar and home buttons (state and icon). Assumes that navigation drawer is NOT visible.
  556. */
  557. protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) {
  558. super.updateActionBarTitleAndHomeButton(chosenFile);
  559. // set home button properties
  560. if (mDrawerToggle != null) {
  561. if (chosenFile != null && isRoot(chosenFile)) {
  562. mDrawerToggle.setDrawerIndicatorEnabled(true);
  563. } else {
  564. mDrawerToggle.setDrawerIndicatorEnabled(false);
  565. }
  566. }
  567. }
  568. /**
  569. * shows or hides the quota UI elements.
  570. *
  571. * @param showQuota show/hide quota information
  572. */
  573. private void showQuota(boolean showQuota) {
  574. if (showQuota) {
  575. mQuotaView.setVisibility(View.VISIBLE);
  576. } else {
  577. mQuotaView.setVisibility(View.GONE);
  578. }
  579. }
  580. /**
  581. * configured the quota to be displayed.
  582. *
  583. * @param usedSpace the used space
  584. * @param totalSpace the total space
  585. * @param relative the percentage of space already used
  586. * @param quotaValue {@link GetUserInfoRemoteOperation#SPACE_UNLIMITED} or other to determinate state
  587. */
  588. private void setQuotaInformation(long usedSpace, long totalSpace, int relative, long quotaValue) {
  589. if (GetUserInfoRemoteOperation.SPACE_UNLIMITED == quotaValue) {
  590. mQuotaTextPercentage.setText(String.format(
  591. getString(R.string.drawer_quota_unlimited),
  592. DisplayUtils.bytesToHumanReadable(usedSpace)));
  593. } else {
  594. mQuotaTextPercentage.setText(String.format(
  595. getString(R.string.drawer_quota),
  596. DisplayUtils.bytesToHumanReadable(usedSpace),
  597. DisplayUtils.bytesToHumanReadable(totalSpace)));
  598. }
  599. mQuotaProgressBar.setProgress(relative);
  600. ThemeBarUtils.colorProgressBar(mQuotaProgressBar, DisplayUtils.getRelativeInfoColor(this, relative));
  601. updateQuotaLink();
  602. showQuota(true);
  603. }
  604. private void unsetAllDrawerMenuItems() {
  605. if (mNavigationView != null) {
  606. mNavigationView.getMenu();
  607. Menu menu = mNavigationView.getMenu();
  608. for (int i = 0; i < menu.size(); i++) {
  609. menu.getItem(i).setChecked(false);
  610. }
  611. }
  612. mCheckedMenuItem = Menu.NONE;
  613. }
  614. private void updateQuotaLink() {
  615. if (mQuotaTextLink != null) {
  616. if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  617. List<ExternalLink> quotas = externalLinksProvider.getExternalLink(ExternalLinkType.QUOTA);
  618. float density = getResources().getDisplayMetrics().density;
  619. final int size = Math.round(24 * density);
  620. if (quotas.size() > 0) {
  621. final ExternalLink firstQuota = quotas.get(0);
  622. mQuotaTextLink.setText(firstQuota.getName());
  623. mQuotaTextLink.setClickable(true);
  624. mQuotaTextLink.setVisibility(View.VISIBLE);
  625. mQuotaTextLink.setOnClickListener(v -> {
  626. Intent externalWebViewIntent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
  627. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, firstQuota.getName());
  628. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, firstQuota.getUrl());
  629. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, true);
  630. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, -1);
  631. startActivity(externalWebViewIntent);
  632. });
  633. SimpleTarget target = new SimpleTarget<Drawable>() {
  634. @Override
  635. public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) {
  636. Drawable test = resource.getCurrent();
  637. test.setBounds(0, 0, size, size);
  638. mQuotaTextLink.setCompoundDrawablesWithIntrinsicBounds(test, null, null, null);
  639. }
  640. @Override
  641. public void onLoadFailed(Exception e, Drawable errorDrawable) {
  642. super.onLoadFailed(e, errorDrawable);
  643. Drawable test = errorDrawable.getCurrent();
  644. test.setBounds(0, 0, size, size);
  645. mQuotaTextLink.setCompoundDrawablesWithIntrinsicBounds(test, null, null, null);
  646. }
  647. };
  648. DisplayUtils.downloadIcon(getUserAccountManager(),
  649. clientFactory,
  650. this,
  651. firstQuota.getIconUrl(),
  652. target,
  653. R.drawable.ic_link,
  654. size,
  655. size);
  656. } else {
  657. mQuotaTextLink.setVisibility(View.GONE);
  658. }
  659. } else {
  660. mQuotaTextLink.setVisibility(View.GONE);
  661. }
  662. }
  663. }
  664. /**
  665. * checks/highlights the provided menu item if the drawer has been initialized and the menu item exists.
  666. *
  667. * @param menuItemId the menu item to be highlighted
  668. */
  669. protected void setDrawerMenuItemChecked(int menuItemId) {
  670. if (mNavigationView != null && mNavigationView.getMenu().findItem(menuItemId) != null) {
  671. mCheckedMenuItem = menuItemId;
  672. MenuItem currentItem = mNavigationView.getMenu().findItem(menuItemId);
  673. int drawerColor = getResources().getColor(R.color.drawer_text_color);
  674. int activeColor = ThemeColorUtils.primaryColor(null, true, true, this);
  675. currentItem.setChecked(true);
  676. // For each menu item, change the color of the selected item, and of the other items
  677. for (int i = 0; i < mNavigationView.getMenu().size(); i++) {
  678. MenuItem menuItem = mNavigationView.getMenu().getItem(i);
  679. if (menuItem.getIcon() != null) {
  680. if (menuItem == currentItem) {
  681. ThemeDrawableUtils.tintDrawable(currentItem.getIcon(), activeColor);
  682. ThemeMenuUtils.tintMenuItemText(currentItem, activeColor);
  683. } else {
  684. ThemeDrawableUtils.tintDrawable(menuItem.getIcon(), drawerColor);
  685. ThemeMenuUtils.tintMenuItemText(menuItem, drawerColor);
  686. }
  687. }
  688. }
  689. } else {
  690. Log_OC.w(TAG, "setDrawerMenuItemChecked has been called with invalid menu-item-ID");
  691. }
  692. }
  693. /**
  694. * Retrieves and shows the user quota if available
  695. */
  696. private void getAndDisplayUserQuota() {
  697. // set user space information
  698. Thread t = new Thread(() -> {
  699. final User user = accountManager.getUser();
  700. if (user.isAnonymous()) {
  701. return;
  702. }
  703. final Context context = MainApp.getAppContext();
  704. NextcloudClient nextcloudClient = null;
  705. try {
  706. nextcloudClient = OwnCloudClientManagerFactory
  707. .getDefaultSingleton()
  708. .getNextcloudClientFor(user.toOwnCloudAccount(),
  709. context);
  710. } catch (OperationCanceledException | AuthenticatorException | IOException e) {
  711. Log_OC.e(this, "Error retrieving user quota", e);
  712. }
  713. if (nextcloudClient == null) {
  714. return;
  715. }
  716. RemoteOperationResult<UserInfo> result = new GetUserInfoRemoteOperation().execute(nextcloudClient);
  717. if (result.isSuccess() && result.getResultData() != null) {
  718. final UserInfo userInfo = result.getResultData();
  719. final Quota quota = userInfo.getQuota();
  720. if (quota != null) {
  721. final long used = quota.getUsed();
  722. final long total = quota.getTotal();
  723. final int relative = (int) Math.ceil(quota.getRelative());
  724. final long quotaValue = quota.getQuota();
  725. runOnUiThread(() -> {
  726. if (quotaValue > 0 || quotaValue == GetUserInfoRemoteOperation.SPACE_UNLIMITED
  727. || quotaValue == GetUserInfoRemoteOperation.QUOTA_LIMIT_INFO_NOT_AVAILABLE) {
  728. /*
  729. * show quota in case
  730. * it is available and calculated (> 0) or
  731. * in case of legacy servers (==QUOTA_LIMIT_INFO_NOT_AVAILABLE)
  732. */
  733. setQuotaInformation(used, total, relative, quotaValue);
  734. } else {
  735. /*
  736. * quotaValue < 0 means special cases like
  737. * {@link RemoteGetUserQuotaOperation.SPACE_NOT_COMPUTED},
  738. * {@link RemoteGetUserQuotaOperation.SPACE_UNKNOWN} or
  739. * {@link RemoteGetUserQuotaOperation.SPACE_UNLIMITED}
  740. * thus don't display any quota information.
  741. */
  742. showQuota(false);
  743. }
  744. });
  745. }
  746. }
  747. });
  748. t.start();
  749. }
  750. private void updateExternalLinksInDrawer() {
  751. if (mNavigationView != null && getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  752. mNavigationView.getMenu().removeGroup(R.id.drawer_menu_external_links);
  753. float density = getResources().getDisplayMetrics().density;
  754. final int size = Math.round(24 * density);
  755. int greyColor = ContextCompat.getColor(this, R.color.drawer_menu_icon);
  756. for (final ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.LINK)) {
  757. int id = mNavigationView.getMenu().add(R.id.drawer_menu_external_links,
  758. MENU_ITEM_EXTERNAL_LINK + link.getId(), MENU_ORDER_EXTERNAL_LINKS, link.getName())
  759. .setCheckable(true).getItemId();
  760. MenuSimpleTarget target = new MenuSimpleTarget<Drawable>(id) {
  761. @Override
  762. public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) {
  763. setExternalLinkIcon(getIdMenuItem(), resource, greyColor);
  764. }
  765. @Override
  766. public void onLoadFailed(Exception e, Drawable errorDrawable) {
  767. super.onLoadFailed(e, errorDrawable);
  768. setExternalLinkIcon(getIdMenuItem(), errorDrawable, greyColor);
  769. }
  770. };
  771. DisplayUtils.downloadIcon(getUserAccountManager(),
  772. clientFactory,
  773. this,
  774. link.getIconUrl(),
  775. target,
  776. R.drawable.ic_link,
  777. size,
  778. size);
  779. }
  780. setDrawerMenuItemChecked(mCheckedMenuItem);
  781. }
  782. }
  783. private void setExternalLinkIcon(int id, Drawable drawable, int greyColor) {
  784. MenuItem menuItem = mNavigationView.getMenu().findItem(id);
  785. if (menuItem != null) {
  786. if (drawable != null) {
  787. menuItem.setIcon(ThemeDrawableUtils.tintDrawable(drawable, greyColor));
  788. } else {
  789. menuItem.setIcon(R.drawable.ic_link);
  790. }
  791. }
  792. }
  793. @Override
  794. protected void onCreate(Bundle savedInstanceState) {
  795. super.onCreate(savedInstanceState);
  796. if (savedInstanceState != null) {
  797. mIsAccountChooserActive = savedInstanceState.getBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, false);
  798. mCheckedMenuItem = savedInstanceState.getInt(KEY_CHECKED_MENU_ITEM, Menu.NONE);
  799. }
  800. externalLinksProvider = new ExternalLinksProvider(getContentResolver());
  801. arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
  802. }
  803. @Override
  804. protected void onSaveInstanceState(@NonNull Bundle outState) {
  805. super.onSaveInstanceState(outState);
  806. outState.putBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, mIsAccountChooserActive);
  807. outState.putInt(KEY_CHECKED_MENU_ITEM, mCheckedMenuItem);
  808. }
  809. @Override
  810. public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
  811. super.onRestoreInstanceState(savedInstanceState);
  812. mIsAccountChooserActive = savedInstanceState.getBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, false);
  813. mCheckedMenuItem = savedInstanceState.getInt(KEY_CHECKED_MENU_ITEM, Menu.NONE);
  814. // check/highlight the menu item if present
  815. if (mCheckedMenuItem > Menu.NONE || mCheckedMenuItem < Menu.NONE) {
  816. setDrawerMenuItemChecked(mCheckedMenuItem);
  817. }
  818. }
  819. @Override
  820. protected void onPostCreate(Bundle savedInstanceState) {
  821. super.onPostCreate(savedInstanceState);
  822. // Sync the toggle state after onRestoreInstanceState has occurred.
  823. if (mDrawerToggle != null) {
  824. mDrawerToggle.syncState();
  825. if (isDrawerOpen()) {
  826. mDrawerToggle.setDrawerIndicatorEnabled(true);
  827. }
  828. }
  829. updateExternalLinksInDrawer();
  830. updateQuotaLink();
  831. }
  832. @Override
  833. public void onConfigurationChanged(@NonNull Configuration newConfig) {
  834. super.onConfigurationChanged(newConfig);
  835. if (mDrawerToggle != null) {
  836. mDrawerToggle.onConfigurationChanged(newConfig);
  837. }
  838. }
  839. @Override
  840. public void onBackPressed() {
  841. if (isDrawerOpen()) {
  842. closeDrawer();
  843. return;
  844. }
  845. Fragment fileDetailsSharingProcessFragment =
  846. getSupportFragmentManager().findFragmentByTag(FileDetailsSharingProcessFragment.TAG);
  847. if (fileDetailsSharingProcessFragment != null) {
  848. ((FileDetailsSharingProcessFragment) fileDetailsSharingProcessFragment).onBackPressed();
  849. } else {
  850. super.onBackPressed();
  851. }
  852. }
  853. @Override
  854. protected void onResume() {
  855. super.onResume();
  856. setDrawerMenuItemChecked(mCheckedMenuItem);
  857. }
  858. @Override
  859. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  860. super.onActivityResult(requestCode, resultCode, data);
  861. // update Account list and active account if Manage Account activity replies with
  862. // - ACCOUNT_LIST_CHANGED = true
  863. // - RESULT_OK
  864. if (requestCode == ACTION_MANAGE_ACCOUNTS && resultCode == RESULT_OK
  865. && data.getBooleanExtra(ManageAccountsActivity.KEY_ACCOUNT_LIST_CHANGED, false)) {
  866. // current account has changed
  867. if (data.getBooleanExtra(ManageAccountsActivity.KEY_CURRENT_ACCOUNT_CHANGED, false)) {
  868. setAccount(accountManager.getCurrentAccount(), false);
  869. restart();
  870. }
  871. } else if (requestCode == PassCodeManager.PASSCODE_ACTIVITY && data != null) {
  872. int result = data.getIntExtra(RequestCredentialsActivity.KEY_CHECK_RESULT,
  873. RequestCredentialsActivity.KEY_CHECK_RESULT_FALSE);
  874. if (result == RequestCredentialsActivity.KEY_CHECK_RESULT_CANCEL) {
  875. Log_OC.d(TAG, "PassCodeManager cancelled");
  876. preferences.setLockTimestamp(0);
  877. finish();
  878. }
  879. }
  880. }
  881. /**
  882. * Quota view can be either at navigation bottom or header
  883. *
  884. * @param id the view's id
  885. * @return The view if found or <code>null</code> otherwise.
  886. */
  887. private View findQuotaViewById(int id) {
  888. View v = ((NavigationView) findViewById(R.id.nav_view)).getHeaderView(0).findViewById(id);
  889. if (v != null) {
  890. return v;
  891. } else {
  892. return findViewById(id);
  893. }
  894. }
  895. /**
  896. * restart helper method which is called after a changing the current account.
  897. */
  898. private void restart() {
  899. Intent i = new Intent(this, FileDisplayActivity.class);
  900. i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  901. i.setAction(FileDisplayActivity.RESTART);
  902. startActivity(i);
  903. fetchExternalLinks(false);
  904. }
  905. /**
  906. * show the file list to the user.
  907. *
  908. * @param onDeviceOnly flag to decide if all files or only the ones on the device should be shown
  909. */
  910. public void showFiles(boolean onDeviceOnly) {
  911. MainApp.showOnlyFilesOnDevice(onDeviceOnly);
  912. Intent fileDisplayActivity = new Intent(getApplicationContext(), FileDisplayActivity.class);
  913. fileDisplayActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  914. startActivity(fileDisplayActivity);
  915. }
  916. @Override
  917. public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
  918. if (callContext instanceof MenuItem) {
  919. MenuItem menuItem = (MenuItem) callContext;
  920. menuItem.setIcon(avatarDrawable);
  921. } else if (callContext instanceof ImageView) {
  922. ImageView imageView = (ImageView) callContext;
  923. imageView.setImageDrawable(avatarDrawable);
  924. } else if (callContext instanceof MaterialButton) {
  925. MaterialButton materialButton = (MaterialButton) callContext;
  926. materialButton.setIcon(avatarDrawable);
  927. }
  928. }
  929. @Override
  930. public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
  931. if (callContext instanceof MenuItem) {
  932. MenuItem menuItem = (MenuItem) callContext;
  933. return String.valueOf(menuItem.getTitle()).equals(tag);
  934. } else if (callContext instanceof ImageView) {
  935. ImageView imageView = (ImageView) callContext;
  936. return String.valueOf(imageView.getTag()).equals(tag);
  937. } else if (callContext instanceof MaterialButton) {
  938. MaterialButton materialButton = (MaterialButton) callContext;
  939. return String.valueOf(materialButton.getTag()).equals(tag);
  940. }
  941. return false;
  942. }
  943. /**
  944. * Adds other listeners to react on changes of the drawer layout.
  945. *
  946. * @param listener Object interested in changes of the drawer layout.
  947. */
  948. public void addDrawerListener(DrawerLayout.DrawerListener listener) {
  949. if (mDrawerLayout != null) {
  950. mDrawerLayout.addDrawerListener(listener);
  951. } else {
  952. Log_OC.e(TAG, "Drawer layout not ready to add drawer listener");
  953. }
  954. }
  955. public boolean isDrawerIndicatorAvailable() {
  956. return true;
  957. }
  958. @Override
  959. protected void onStart() {
  960. super.onStart();
  961. EventBus.getDefault().register(this);
  962. }
  963. @Override
  964. protected void onStop() {
  965. if (preferences.getLockTimestamp() != 0) {
  966. preferences.setLockTimestamp(SystemClock.elapsedRealtime());
  967. }
  968. EventBus.getDefault().unregister(this);
  969. super.onStop();
  970. }
  971. @Subscribe(threadMode = ThreadMode.MAIN)
  972. public void onAccountRemovedEvent(AccountRemovedEvent event) {
  973. restart();
  974. }
  975. /**
  976. * Retrieves external links via api from 'external' app
  977. */
  978. public void fetchExternalLinks(final boolean force) {
  979. if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  980. Thread t = new Thread(() -> {
  981. // fetch capabilities as early as possible
  982. if ((getCapabilities() == null || getCapabilities().getAccountName().isEmpty())
  983. && getStorageManager() != null) {
  984. GetCapabilitiesOperation getCapabilities = new GetCapabilitiesOperation(getStorageManager());
  985. getCapabilities.execute(getBaseContext());
  986. }
  987. User user = accountManager.getUser();
  988. String name = user.getAccountName();
  989. if (getStorageManager() != null && getStorageManager().getCapability(name).getExternalLinks().isTrue()) {
  990. int count = arbitraryDataProvider.getIntegerValue(FilesSyncHelper.GLOBAL,
  991. FileActivity.APP_OPENED_COUNT);
  992. if (count > 10 || count == -1 || force) {
  993. if (force) {
  994. Log_OC.d("ExternalLinks", "force update");
  995. }
  996. arbitraryDataProvider.storeOrUpdateKeyValue(FilesSyncHelper.GLOBAL,
  997. FileActivity.APP_OPENED_COUNT, "0");
  998. Log_OC.d("ExternalLinks", "update via api");
  999. RemoteOperation getExternalLinksOperation = new ExternalLinksOperation();
  1000. RemoteOperationResult result = getExternalLinksOperation.execute(user.toPlatformAccount(), this);
  1001. if (result.isSuccess() && result.getData() != null) {
  1002. externalLinksProvider.deleteAllExternalLinks();
  1003. ArrayList<ExternalLink> externalLinks = (ArrayList<ExternalLink>) (Object) result.getData();
  1004. for (ExternalLink link : externalLinks) {
  1005. externalLinksProvider.storeExternalLink(link);
  1006. }
  1007. }
  1008. } else {
  1009. arbitraryDataProvider.storeOrUpdateKeyValue(FilesSyncHelper.GLOBAL,
  1010. FileActivity.APP_OPENED_COUNT, String.valueOf(count + 1));
  1011. }
  1012. } else {
  1013. externalLinksProvider.deleteAllExternalLinks();
  1014. Log_OC.d("ExternalLinks", "links disabled");
  1015. }
  1016. runOnUiThread(this::updateExternalLinksInDrawer);
  1017. });
  1018. t.start();
  1019. }
  1020. }
  1021. }