DrawerActivity.java 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  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.preview.PreviewTextStringFragment;
  103. import com.owncloud.android.ui.trashbin.TrashbinActivity;
  104. import com.owncloud.android.utils.BitmapUtils;
  105. import com.owncloud.android.utils.DisplayUtils;
  106. import com.owncloud.android.utils.DrawerMenuUtil;
  107. import com.owncloud.android.utils.FilesSyncHelper;
  108. import com.owncloud.android.utils.svg.MenuSimpleTarget;
  109. import com.owncloud.android.utils.svg.SVGorImage;
  110. import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder;
  111. import com.owncloud.android.utils.svg.SvgOrImageDecoder;
  112. import com.owncloud.android.utils.theme.ThemeBarUtils;
  113. import com.owncloud.android.utils.theme.ThemeColorUtils;
  114. import com.owncloud.android.utils.theme.ThemeDrawableUtils;
  115. import com.owncloud.android.utils.theme.ThemeMenuUtils;
  116. import org.greenrobot.eventbus.EventBus;
  117. import org.greenrobot.eventbus.Subscribe;
  118. import org.greenrobot.eventbus.ThreadMode;
  119. import java.io.IOException;
  120. import java.io.InputStream;
  121. import java.util.ArrayList;
  122. import java.util.List;
  123. import javax.inject.Inject;
  124. import androidx.annotation.NonNull;
  125. import androidx.appcompat.app.ActionBarDrawerToggle;
  126. import androidx.core.content.ContextCompat;
  127. import androidx.core.content.res.ResourcesCompat;
  128. import androidx.core.view.GravityCompat;
  129. import androidx.drawerlayout.widget.DrawerLayout;
  130. import androidx.fragment.app.Fragment;
  131. /**
  132. * Base class to handle setup of the drawer implementation including user switching and avatar fetching and fallback
  133. * generation.
  134. */
  135. public abstract class DrawerActivity extends ToolbarActivity
  136. implements DisplayUtils.AvatarGenerationListener, Injectable {
  137. private static final String TAG = DrawerActivity.class.getSimpleName();
  138. private static final String KEY_IS_ACCOUNT_CHOOSER_ACTIVE = "IS_ACCOUNT_CHOOSER_ACTIVE";
  139. private static final String KEY_CHECKED_MENU_ITEM = "CHECKED_MENU_ITEM";
  140. private static final int ACTION_MANAGE_ACCOUNTS = 101;
  141. private static final int MENU_ORDER_EXTERNAL_LINKS = 3;
  142. private static final int MENU_ITEM_EXTERNAL_LINK = 111;
  143. private static final int MAX_LOGO_SIZE_PX = 1000;
  144. /**
  145. * Reference to the drawer layout.
  146. */
  147. private DrawerLayout mDrawerLayout;
  148. /**
  149. * Reference to the drawer toggle.
  150. */
  151. protected ActionBarDrawerToggle mDrawerToggle;
  152. /**
  153. * Reference to the navigation view.
  154. */
  155. private NavigationView mNavigationView;
  156. /**
  157. * Reference to the navigation view header.
  158. */
  159. private View mNavigationViewHeader;
  160. /**
  161. * Flag to signal if the account chooser is active.
  162. */
  163. private boolean mIsAccountChooserActive;
  164. /**
  165. * Id of the checked menu item.
  166. */
  167. private int mCheckedMenuItem = Menu.NONE;
  168. /**
  169. * container layout of the quota view.
  170. */
  171. private LinearLayout mQuotaView;
  172. /**
  173. * progress bar of the quota view.
  174. */
  175. private ProgressBar mQuotaProgressBar;
  176. /**
  177. * text view of the quota view.
  178. */
  179. private TextView mQuotaTextPercentage;
  180. private TextView mQuotaTextLink;
  181. /**
  182. * runnable that will be executed after the drawer has been closed.
  183. */
  184. private Runnable pendingRunnable;
  185. private ExternalLinksProvider externalLinksProvider;
  186. private ArbitraryDataProvider arbitraryDataProvider;
  187. @Inject
  188. AppPreferences preferences;
  189. @Inject
  190. ClientFactory clientFactory;
  191. /**
  192. * Initializes the drawer, its content and highlights the menu item with the given id. This method needs to be
  193. * called after the content view has been set.
  194. *
  195. * @param menuItemId the menu item to be checked/highlighted
  196. */
  197. protected void setupDrawer(int menuItemId) {
  198. setupDrawer();
  199. setDrawerMenuItemChecked(menuItemId);
  200. }
  201. /**
  202. * Initializes the drawer and its content. This method needs to be called after the content view has been set.
  203. */
  204. protected void setupDrawer() {
  205. mDrawerLayout = findViewById(R.id.drawer_layout);
  206. mNavigationView = findViewById(R.id.nav_view);
  207. if (mNavigationView != null) {
  208. // Setting up drawer header
  209. mNavigationViewHeader = mNavigationView.getHeaderView(0);
  210. updateHeader();
  211. setupDrawerMenu(mNavigationView);
  212. getAndDisplayUserQuota();
  213. setupQuotaElement();
  214. }
  215. setupDrawerToggle();
  216. if (getSupportActionBar() != null) {
  217. getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  218. }
  219. }
  220. /**
  221. * initializes and sets up the drawer toggle.
  222. */
  223. private void setupDrawerToggle() {
  224. mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
  225. /** Called when a drawer has settled in a completely closed state. */
  226. public void onDrawerClosed(View view) {
  227. super.onDrawerClosed(view);
  228. supportInvalidateOptionsMenu();
  229. mDrawerToggle.setDrawerIndicatorEnabled(isDrawerIndicatorAvailable());
  230. if (pendingRunnable != null) {
  231. new Handler().post(pendingRunnable);
  232. pendingRunnable = null;
  233. }
  234. closeDrawer();
  235. }
  236. /** Called when a drawer has settled in a completely open state. */
  237. public void onDrawerOpened(View drawerView) {
  238. super.onDrawerOpened(drawerView);
  239. mDrawerToggle.setDrawerIndicatorEnabled(true);
  240. supportInvalidateOptionsMenu();
  241. }
  242. };
  243. // Set the drawer toggle as the DrawerListener
  244. mDrawerLayout.addDrawerListener(mDrawerToggle);
  245. mDrawerToggle.setDrawerIndicatorEnabled(true);
  246. mDrawerToggle.setDrawerSlideAnimationEnabled(true);
  247. Drawable backArrow = ResourcesCompat.getDrawable(getResources(),
  248. R.drawable.ic_arrow_back,
  249. null);
  250. mDrawerToggle.setHomeAsUpIndicator(
  251. ThemeDrawableUtils.tintDrawable(backArrow, ThemeColorUtils.appBarPrimaryFontColor(this)));
  252. mDrawerToggle.getDrawerArrowDrawable().setColor(ThemeColorUtils.appBarPrimaryFontColor(this));
  253. }
  254. /**
  255. * setup quota elements of the drawer.
  256. */
  257. private void setupQuotaElement() {
  258. mQuotaView = (LinearLayout) findQuotaViewById(R.id.drawer_quota);
  259. mQuotaProgressBar = (ProgressBar) findQuotaViewById(R.id.drawer_quota_ProgressBar);
  260. mQuotaTextPercentage = (TextView) findQuotaViewById(R.id.drawer_quota_percentage);
  261. mQuotaTextLink = (TextView) findQuotaViewById(R.id.drawer_quota_link);
  262. ThemeBarUtils.colorProgressBar(mQuotaProgressBar, ThemeColorUtils.primaryColor(this));
  263. }
  264. public void updateHeader() {
  265. if (getAccount() != null &&
  266. getStorageManager().getCapability(getAccount().name).getServerBackground() != null) {
  267. OCCapability capability = getStorageManager().getCapability(getAccount().name);
  268. String logo = capability.getServerLogo();
  269. int primaryColor = ThemeColorUtils.primaryColor(getAccount(), false, this);
  270. // set background to primary color
  271. LinearLayout drawerHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_view);
  272. drawerHeader.setBackgroundColor(ThemeColorUtils.unchangedPrimaryColor(getAccount(), this));
  273. if (!TextUtils.isEmpty(logo) && URLUtil.isValidUrl(logo)) {
  274. // background image
  275. GenericRequestBuilder<Uri, InputStream, SVGorImage, Bitmap> requestBuilder = Glide.with(this)
  276. .using(Glide.buildStreamModelLoader(Uri.class, this), InputStream.class)
  277. .from(Uri.class)
  278. .as(SVGorImage.class)
  279. .transcode(new SvgOrImageBitmapTranscoder(128, 128), Bitmap.class)
  280. .sourceEncoder(new StreamEncoder())
  281. .cacheDecoder(new FileToStreamDecoder<>(new SvgOrImageDecoder()))
  282. .decoder(new SvgOrImageDecoder());
  283. // background image
  284. SimpleTarget target = new SimpleTarget<Bitmap>() {
  285. @Override
  286. public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
  287. Bitmap logo = resource;
  288. int width = resource.getWidth();
  289. int height = resource.getHeight();
  290. int max = Math.max(width, height);
  291. if (max > MAX_LOGO_SIZE_PX) {
  292. logo = BitmapUtils.scaleBitmap(resource, MAX_LOGO_SIZE_PX, width, height, max);
  293. }
  294. Drawable[] drawables = {new ColorDrawable(primaryColor), new BitmapDrawable(logo)};
  295. LayerDrawable layerDrawable = new LayerDrawable(drawables);
  296. String name = capability.getServerName();
  297. setDrawerHeaderLogo(layerDrawable, name);
  298. }
  299. };
  300. requestBuilder
  301. .diskCacheStrategy(DiskCacheStrategy.SOURCE)
  302. .load(Uri.parse(logo))
  303. .into(target);
  304. }
  305. }
  306. }
  307. private void setDrawerHeaderLogo(Drawable drawable, String name) {
  308. ImageView imageHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_logo);
  309. imageHeader.setImageDrawable(drawable);
  310. imageHeader.setScaleType(ImageView.ScaleType.FIT_START);
  311. imageHeader.setAdjustViewBounds(true);
  312. imageHeader.setMaxWidth(DisplayUtils.convertDpToPixel(100f, this));
  313. MarginLayoutParams oldParam = (MarginLayoutParams) imageHeader.getLayoutParams();
  314. MarginLayoutParams params = new MarginLayoutParams(LayoutParams.WRAP_CONTENT,
  315. LayoutParams.MATCH_PARENT);
  316. params.leftMargin = oldParam.leftMargin;
  317. params.rightMargin = oldParam.rightMargin;
  318. imageHeader.setLayoutParams(new LinearLayout.LayoutParams(params));
  319. if (!TextUtils.isEmpty(name)) {
  320. TextView serverName = mNavigationViewHeader.findViewById(R.id.drawer_header_server_name);
  321. serverName.setText(name);
  322. serverName.setTextColor(ThemeColorUtils.unchangedFontColor(this));
  323. }
  324. }
  325. /**
  326. * setup drawer header, basically the logo color
  327. */
  328. private void setupDrawerHeader(FrameLayout drawerHeader) {
  329. drawerHeader.setBackgroundColor(ThemeColorUtils.primaryColor(getAccount(), true, this));
  330. }
  331. /**
  332. * setup drawer content, basically setting the item selected listener.
  333. *
  334. * @param navigationView the drawers navigation view
  335. */
  336. private void setupDrawerMenu(NavigationView navigationView) {
  337. navigationView.setItemIconTintList(null);
  338. // setup actions for drawer menu items
  339. navigationView.setNavigationItemSelectedListener(
  340. menuItem -> {
  341. mDrawerLayout.closeDrawers();
  342. // pending runnable will be executed after the drawer has been closed
  343. pendingRunnable = () -> onNavigationItemClicked(menuItem);
  344. return true;
  345. });
  346. User account = accountManager.getUser();
  347. filterDrawerMenu(navigationView.getMenu(), account);
  348. }
  349. private void filterDrawerMenu(final Menu menu, @NonNull final User user) {
  350. FileDataStorageManager storageManager = new FileDataStorageManager(user,
  351. getContentResolver());
  352. OCCapability capability = storageManager.getCapability(user.getAccountName());
  353. DrawerMenuUtil.filterSearchMenuItems(menu, user, getResources());
  354. DrawerMenuUtil.filterTrashbinMenuItem(menu, capability);
  355. DrawerMenuUtil.filterActivityMenuItem(menu, capability);
  356. DrawerMenuUtil.setupHomeMenuItem(menu, getResources());
  357. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_community,
  358. !getResources().getBoolean(R.bool.participate_enabled));
  359. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_shared, !getResources().getBoolean(R.bool.shared_enabled));
  360. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout));
  361. }
  362. @Subscribe(threadMode = ThreadMode.MAIN)
  363. public void onMessageEvent(DummyDrawerEvent event) {
  364. unsetAllDrawerMenuItems();
  365. }
  366. private void onNavigationItemClicked(final MenuItem menuItem) {
  367. setDrawerMenuItemChecked(menuItem.getItemId());
  368. int itemId = menuItem.getItemId();
  369. if (itemId == R.id.nav_all_files) {
  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. }