DrawerActivity.java 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  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.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 org.parceler.Parcels;
  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. /**
  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. Drawable[] drawables = {new ColorDrawable(primaryColor), new BitmapDrawable(resource)};
  287. LayerDrawable layerDrawable = new LayerDrawable(drawables);
  288. String name = capability.getServerName();
  289. setDrawerHeaderLogo(layerDrawable, name);
  290. }
  291. };
  292. requestBuilder
  293. .diskCacheStrategy(DiskCacheStrategy.SOURCE)
  294. .load(Uri.parse(logo))
  295. .into(target);
  296. }
  297. }
  298. }
  299. private void setDrawerHeaderLogo(Drawable drawable, String name) {
  300. ImageView imageHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_logo);
  301. imageHeader.setImageDrawable(drawable);
  302. imageHeader.setScaleType(ImageView.ScaleType.FIT_START);
  303. imageHeader.setAdjustViewBounds(true);
  304. imageHeader.setMaxWidth(DisplayUtils.convertDpToPixel(100f, this));
  305. MarginLayoutParams oldParam = (MarginLayoutParams) imageHeader.getLayoutParams();
  306. MarginLayoutParams params = new MarginLayoutParams(LayoutParams.WRAP_CONTENT,
  307. LayoutParams.MATCH_PARENT);
  308. params.leftMargin = oldParam.leftMargin;
  309. params.rightMargin = oldParam.rightMargin;
  310. imageHeader.setLayoutParams(new LinearLayout.LayoutParams(params));
  311. if (!TextUtils.isEmpty(name)) {
  312. TextView serverName = mNavigationViewHeader.findViewById(R.id.drawer_header_server_name);
  313. serverName.setText(name);
  314. serverName.setTextColor(ThemeColorUtils.unchangedFontColor(this));
  315. }
  316. }
  317. /**
  318. * setup drawer header, basically the logo color
  319. */
  320. private void setupDrawerHeader(FrameLayout drawerHeader) {
  321. drawerHeader.setBackgroundColor(ThemeColorUtils.primaryColor(getAccount(), true, this));
  322. }
  323. /**
  324. * setup drawer content, basically setting the item selected listener.
  325. *
  326. * @param navigationView the drawers navigation view
  327. */
  328. private void setupDrawerMenu(NavigationView navigationView) {
  329. navigationView.setItemIconTintList(null);
  330. // setup actions for drawer menu items
  331. navigationView.setNavigationItemSelectedListener(
  332. menuItem -> {
  333. mDrawerLayout.closeDrawers();
  334. // pending runnable will be executed after the drawer has been closed
  335. pendingRunnable = () -> onNavigationItemClicked(menuItem);
  336. return true;
  337. });
  338. User account = accountManager.getUser();
  339. filterDrawerMenu(navigationView.getMenu(), account);
  340. }
  341. private void filterDrawerMenu(final Menu menu, @NonNull final User user) {
  342. FileDataStorageManager storageManager = new FileDataStorageManager(user,
  343. getContentResolver());
  344. OCCapability capability = storageManager.getCapability(user.getAccountName());
  345. DrawerMenuUtil.filterSearchMenuItems(menu, user, getResources());
  346. DrawerMenuUtil.filterTrashbinMenuItem(menu, capability);
  347. DrawerMenuUtil.filterActivityMenuItem(menu, capability);
  348. DrawerMenuUtil.setupHomeMenuItem(menu, getResources());
  349. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_community,
  350. !getResources().getBoolean(R.bool.participate_enabled));
  351. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_shared, !getResources().getBoolean(R.bool.shared_enabled));
  352. DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout));
  353. }
  354. @Subscribe(threadMode = ThreadMode.MAIN)
  355. public void onMessageEvent(DummyDrawerEvent event) {
  356. unsetAllDrawerMenuItems();
  357. }
  358. private void onNavigationItemClicked(final MenuItem menuItem) {
  359. setDrawerMenuItemChecked(menuItem.getItemId());
  360. int itemId = menuItem.getItemId();
  361. if (itemId == R.id.nav_all_files) {
  362. if (this instanceof FileDisplayActivity &&
  363. !(((FileDisplayActivity) this).getLeftFragment() instanceof GalleryFragment) &&
  364. !(((FileDisplayActivity) this).getLeftFragment() instanceof PreviewTextStringFragment)) {
  365. showFiles(false);
  366. ((FileDisplayActivity) this).browseToRoot();
  367. EventBus.getDefault().post(new ChangeMenuEvent());
  368. } else {
  369. Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
  370. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  371. intent.setAction(FileDisplayActivity.ALL_FILES);
  372. intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItem.getItemId());
  373. startActivity(intent);
  374. }
  375. } else if (itemId == R.id.nav_favorites) {
  376. handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH),
  377. menuItem.getItemId());
  378. } else if (itemId == R.id.nav_gallery) {
  379. startPhotoSearch(menuItem);
  380. } else if (itemId == R.id.nav_on_device) {
  381. EventBus.getDefault().post(new ChangeMenuEvent());
  382. showFiles(true);
  383. } else if (itemId == R.id.nav_uploads) {
  384. startActivity(UploadListActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
  385. } else if (itemId == R.id.nav_trashbin) {
  386. startActivity(TrashbinActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
  387. } else if (itemId == R.id.nav_activity) {
  388. startActivity(ActivitiesActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
  389. } else if (itemId == R.id.nav_notifications) {
  390. startActivity(NotificationsActivity.class);
  391. } else if (itemId == R.id.nav_settings) {
  392. startActivity(SettingsActivity.class);
  393. } else if (itemId == R.id.nav_community) {
  394. startActivity(CommunityActivity.class);
  395. } else if (itemId == R.id.nav_logout) {
  396. mCheckedMenuItem = -1;
  397. menuItem.setChecked(false);
  398. final Optional<User> optionalUser = getUser();
  399. if (optionalUser.isPresent()) {
  400. UserInfoActivity.openAccountRemovalConfirmationDialog(optionalUser.get(), getSupportFragmentManager());
  401. }
  402. } else if (itemId == R.id.nav_shared) {
  403. handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.SHARED_FILTER),
  404. menuItem.getItemId());
  405. } else if (itemId == R.id.nav_recently_modified) {
  406. handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.RECENTLY_MODIFIED_SEARCH),
  407. menuItem.getItemId());
  408. } else {
  409. if (menuItem.getItemId() >= MENU_ITEM_EXTERNAL_LINK &&
  410. menuItem.getItemId() <= MENU_ITEM_EXTERNAL_LINK + 100) {
  411. // external link clicked
  412. externalLinkClicked(menuItem);
  413. } else {
  414. Log_OC.w(TAG, "Unknown drawer menu item clicked: " + menuItem.getTitle());
  415. }
  416. }
  417. }
  418. private void startActivity(Class<? extends Activity> activity) {
  419. startActivity(new Intent(getApplicationContext(), activity));
  420. }
  421. private void startActivity(Class<? extends Activity> activity, int flags) {
  422. Intent intent = new Intent(getApplicationContext(), activity);
  423. intent.setFlags(flags);
  424. startActivity(intent);
  425. }
  426. public void showManageAccountsDialog() {
  427. ChooseAccountDialogFragment choseAccountDialog = ChooseAccountDialogFragment.newInstance(accountManager.getUser());
  428. choseAccountDialog.show(getSupportFragmentManager(), "fragment_chose_account");
  429. }
  430. public void openManageAccounts() {
  431. Intent manageAccountsIntent = new Intent(getApplicationContext(), ManageAccountsActivity.class);
  432. startActivityForResult(manageAccountsIntent, ACTION_MANAGE_ACCOUNTS);
  433. }
  434. public void openAddAccount() {
  435. boolean isProviderOrOwnInstallationVisible = getResources()
  436. .getBoolean(R.bool.show_provider_or_own_installation);
  437. if (isProviderOrOwnInstallationVisible) {
  438. Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
  439. firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
  440. startActivity(firstRunIntent);
  441. } else {
  442. startAccountCreation();
  443. }
  444. }
  445. private void startPhotoSearch(MenuItem menuItem) {
  446. SearchEvent searchEvent = new SearchEvent("image/%", SearchRemoteOperation.SearchType.PHOTO_SEARCH);
  447. MainApp.showOnlyFilesOnDevice(false);
  448. Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
  449. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  450. intent.setAction(Intent.ACTION_SEARCH);
  451. intent.putExtra(OCFileListFragment.SEARCH_EVENT, Parcels.wrap(searchEvent));
  452. intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItem.getItemId());
  453. startActivity(intent);
  454. }
  455. private void handleSearchEvents(SearchEvent searchEvent, int menuItemId) {
  456. if (this instanceof FileDisplayActivity) {
  457. if (((FileDisplayActivity) this).getListOfFilesFragment() instanceof GalleryFragment) {
  458. Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
  459. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  460. intent.setAction(Intent.ACTION_SEARCH);
  461. intent.putExtra(OCFileListFragment.SEARCH_EVENT, Parcels.wrap(searchEvent));
  462. intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItemId);
  463. startActivity(intent);
  464. } else {
  465. EventBus.getDefault().post(searchEvent);
  466. }
  467. } else {
  468. Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
  469. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  470. intent.setAction(Intent.ACTION_SEARCH);
  471. intent.putExtra(OCFileListFragment.SEARCH_EVENT, Parcels.wrap(searchEvent));
  472. intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItemId);
  473. startActivity(intent);
  474. }
  475. }
  476. /**
  477. * sets the new/current account and restarts. In case the given account equals the actual/current account the call
  478. * will be ignored.
  479. *
  480. * @param hashCode HashCode of account to be set
  481. */
  482. public void accountClicked(int hashCode) {
  483. final User currentUser = accountManager.getUser();
  484. if (currentUser.hashCode() != hashCode && accountManager.setCurrentOwnCloudAccount(hashCode)) {
  485. fetchExternalLinks(true);
  486. restart();
  487. }
  488. }
  489. private void externalLinkClicked(MenuItem menuItem) {
  490. for (ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.LINK)) {
  491. if (menuItem.getTitle().toString().equalsIgnoreCase(link.name)) {
  492. if (link.redirect) {
  493. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link.url));
  494. DisplayUtils.startIntentIfAppAvailable(intent, this, R.string.no_browser_available);
  495. } else {
  496. Intent externalWebViewIntent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
  497. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, link.name);
  498. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, link.url);
  499. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, true);
  500. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, menuItem.getItemId());
  501. startActivity(externalWebViewIntent);
  502. }
  503. }
  504. }
  505. }
  506. /**
  507. * checks if the drawer exists and is opened.
  508. *
  509. * @return <code>true</code> if the drawer is open, else <code>false</code>
  510. */
  511. public boolean isDrawerOpen() {
  512. return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START);
  513. }
  514. /**
  515. * closes the drawer.
  516. */
  517. public void closeDrawer() {
  518. if (mDrawerLayout != null) {
  519. mDrawerLayout.closeDrawer(GravityCompat.START);
  520. }
  521. }
  522. /**
  523. * opens the drawer.
  524. */
  525. public void openDrawer() {
  526. if (mDrawerLayout != null) {
  527. mDrawerLayout.openDrawer(GravityCompat.START);
  528. updateExternalLinksInDrawer();
  529. updateQuotaLink();
  530. }
  531. }
  532. /**
  533. * Enable or disable interaction with all drawers.
  534. *
  535. * @param lockMode The new lock mode for the given drawer. One of {@link DrawerLayout#LOCK_MODE_UNLOCKED}, {@link
  536. * DrawerLayout#LOCK_MODE_LOCKED_CLOSED} or {@link DrawerLayout#LOCK_MODE_LOCKED_OPEN}.
  537. */
  538. public void setDrawerLockMode(int lockMode) {
  539. if (mDrawerLayout != null) {
  540. mDrawerLayout.setDrawerLockMode(lockMode);
  541. }
  542. }
  543. /**
  544. * Enable or disable the drawer indicator.
  545. *
  546. * @param enable true to enable, false to disable
  547. */
  548. public void setDrawerIndicatorEnabled(boolean enable) {
  549. if (mDrawerToggle != null) {
  550. mDrawerToggle.setDrawerIndicatorEnabled(enable);
  551. }
  552. }
  553. /**
  554. * Updates title bar and home buttons (state and icon). Assumes that navigation drawer is NOT visible.
  555. */
  556. protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) {
  557. super.updateActionBarTitleAndHomeButton(chosenFile);
  558. // set home button properties
  559. if (mDrawerToggle != null) {
  560. if (chosenFile != null && isRoot(chosenFile)) {
  561. mDrawerToggle.setDrawerIndicatorEnabled(true);
  562. } else {
  563. mDrawerToggle.setDrawerIndicatorEnabled(false);
  564. }
  565. }
  566. }
  567. /**
  568. * shows or hides the quota UI elements.
  569. *
  570. * @param showQuota show/hide quota information
  571. */
  572. private void showQuota(boolean showQuota) {
  573. if (showQuota) {
  574. mQuotaView.setVisibility(View.VISIBLE);
  575. } else {
  576. mQuotaView.setVisibility(View.GONE);
  577. }
  578. }
  579. /**
  580. * configured the quota to be displayed.
  581. *
  582. * @param usedSpace the used space
  583. * @param totalSpace the total space
  584. * @param relative the percentage of space already used
  585. * @param quotaValue {@link GetUserInfoRemoteOperation#SPACE_UNLIMITED} or other to determinate state
  586. */
  587. private void setQuotaInformation(long usedSpace, long totalSpace, int relative, long quotaValue) {
  588. if (GetUserInfoRemoteOperation.SPACE_UNLIMITED == quotaValue) {
  589. mQuotaTextPercentage.setText(String.format(
  590. getString(R.string.drawer_quota_unlimited),
  591. DisplayUtils.bytesToHumanReadable(usedSpace)));
  592. } else {
  593. mQuotaTextPercentage.setText(String.format(
  594. getString(R.string.drawer_quota),
  595. DisplayUtils.bytesToHumanReadable(usedSpace),
  596. DisplayUtils.bytesToHumanReadable(totalSpace)));
  597. }
  598. mQuotaProgressBar.setProgress(relative);
  599. ThemeBarUtils.colorProgressBar(mQuotaProgressBar, DisplayUtils.getRelativeInfoColor(this, relative));
  600. updateQuotaLink();
  601. showQuota(true);
  602. }
  603. private void unsetAllDrawerMenuItems() {
  604. if (mNavigationView != null) {
  605. mNavigationView.getMenu();
  606. Menu menu = mNavigationView.getMenu();
  607. for (int i = 0; i < menu.size(); i++) {
  608. menu.getItem(i).setChecked(false);
  609. }
  610. }
  611. mCheckedMenuItem = Menu.NONE;
  612. }
  613. private void updateQuotaLink() {
  614. if (mQuotaTextLink != null) {
  615. if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  616. List<ExternalLink> quotas = externalLinksProvider.getExternalLink(ExternalLinkType.QUOTA);
  617. float density = getResources().getDisplayMetrics().density;
  618. final int size = Math.round(24 * density);
  619. if (quotas.size() > 0) {
  620. final ExternalLink firstQuota = quotas.get(0);
  621. mQuotaTextLink.setText(firstQuota.name);
  622. mQuotaTextLink.setClickable(true);
  623. mQuotaTextLink.setVisibility(View.VISIBLE);
  624. mQuotaTextLink.setOnClickListener(v -> {
  625. Intent externalWebViewIntent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
  626. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, firstQuota.name);
  627. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, firstQuota.url);
  628. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, true);
  629. externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, -1);
  630. startActivity(externalWebViewIntent);
  631. });
  632. SimpleTarget target = new SimpleTarget<Drawable>() {
  633. @Override
  634. public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) {
  635. Drawable test = resource.getCurrent();
  636. test.setBounds(0, 0, size, size);
  637. mQuotaTextLink.setCompoundDrawablesWithIntrinsicBounds(test, null, null, null);
  638. }
  639. @Override
  640. public void onLoadFailed(Exception e, Drawable errorDrawable) {
  641. super.onLoadFailed(e, errorDrawable);
  642. Drawable test = errorDrawable.getCurrent();
  643. test.setBounds(0, 0, size, size);
  644. mQuotaTextLink.setCompoundDrawablesWithIntrinsicBounds(test, null, null, null);
  645. }
  646. };
  647. DisplayUtils.downloadIcon(getUserAccountManager(),
  648. clientFactory,
  649. this,
  650. firstQuota.iconUrl,
  651. target,
  652. R.drawable.ic_link,
  653. size,
  654. size);
  655. } else {
  656. mQuotaTextLink.setVisibility(View.GONE);
  657. }
  658. } else {
  659. mQuotaTextLink.setVisibility(View.GONE);
  660. }
  661. }
  662. }
  663. /**
  664. * checks/highlights the provided menu item if the drawer has been initialized and the menu item exists.
  665. *
  666. * @param menuItemId the menu item to be highlighted
  667. */
  668. protected void setDrawerMenuItemChecked(int menuItemId) {
  669. if (mNavigationView != null && mNavigationView.getMenu().findItem(menuItemId) != null) {
  670. mCheckedMenuItem = menuItemId;
  671. MenuItem currentItem = mNavigationView.getMenu().findItem(menuItemId);
  672. int drawerColor = getResources().getColor(R.color.drawer_text_color);
  673. int activeColor = ThemeColorUtils.primaryColor(null, true, true, this);
  674. currentItem.setChecked(true);
  675. // For each menu item, change the color of the selected item, and of the other items
  676. for (int i = 0; i < mNavigationView.getMenu().size(); i++) {
  677. MenuItem menuItem = mNavigationView.getMenu().getItem(i);
  678. if (menuItem.getIcon() != null) {
  679. if (menuItem == currentItem) {
  680. ThemeDrawableUtils.tintDrawable(currentItem.getIcon(), activeColor);
  681. ThemeMenuUtils.tintMenuItemText(currentItem, activeColor);
  682. } else {
  683. ThemeDrawableUtils.tintDrawable(menuItem.getIcon(), drawerColor);
  684. ThemeMenuUtils.tintMenuItemText(menuItem, drawerColor);
  685. }
  686. }
  687. }
  688. } else {
  689. Log_OC.w(TAG, "setDrawerMenuItemChecked has been called with invalid menu-item-ID");
  690. }
  691. }
  692. /**
  693. * Retrieves and shows the user quota if available
  694. */
  695. private void getAndDisplayUserQuota() {
  696. // set user space information
  697. Thread t = new Thread(() -> {
  698. final User user = accountManager.getUser();
  699. if (user.isAnonymous()) {
  700. return;
  701. }
  702. final Context context = MainApp.getAppContext();
  703. NextcloudClient nextcloudClient = null;
  704. try {
  705. nextcloudClient = OwnCloudClientManagerFactory
  706. .getDefaultSingleton()
  707. .getNextcloudClientFor(user.toOwnCloudAccount(),
  708. context);
  709. } catch (OperationCanceledException | AuthenticatorException | IOException e) {
  710. Log_OC.e(this, "Error retrieving user quota", e);
  711. }
  712. if (nextcloudClient == null) {
  713. return;
  714. }
  715. RemoteOperationResult<UserInfo> result = new GetUserInfoRemoteOperation().execute(nextcloudClient);
  716. if (result.isSuccess() && result.getResultData() != null) {
  717. final UserInfo userInfo = result.getResultData();
  718. final Quota quota = userInfo.getQuota();
  719. if (quota != null) {
  720. final long used = quota.getUsed();
  721. final long total = quota.getTotal();
  722. final int relative = (int) Math.ceil(quota.getRelative());
  723. final long quotaValue = quota.getQuota();
  724. runOnUiThread(() -> {
  725. if (quotaValue > 0 || quotaValue == GetUserInfoRemoteOperation.SPACE_UNLIMITED
  726. || quotaValue == GetUserInfoRemoteOperation.QUOTA_LIMIT_INFO_NOT_AVAILABLE) {
  727. /*
  728. * show quota in case
  729. * it is available and calculated (> 0) or
  730. * in case of legacy servers (==QUOTA_LIMIT_INFO_NOT_AVAILABLE)
  731. */
  732. setQuotaInformation(used, total, relative, quotaValue);
  733. } else {
  734. /*
  735. * quotaValue < 0 means special cases like
  736. * {@link RemoteGetUserQuotaOperation.SPACE_NOT_COMPUTED},
  737. * {@link RemoteGetUserQuotaOperation.SPACE_UNKNOWN} or
  738. * {@link RemoteGetUserQuotaOperation.SPACE_UNLIMITED}
  739. * thus don't display any quota information.
  740. */
  741. showQuota(false);
  742. }
  743. });
  744. }
  745. }
  746. });
  747. t.start();
  748. }
  749. private void updateExternalLinksInDrawer() {
  750. if (mNavigationView != null && getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  751. mNavigationView.getMenu().removeGroup(R.id.drawer_menu_external_links);
  752. float density = getResources().getDisplayMetrics().density;
  753. final int size = Math.round(24 * density);
  754. int greyColor = ContextCompat.getColor(this, R.color.drawer_menu_icon);
  755. for (final ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.LINK)) {
  756. int id = mNavigationView.getMenu().add(R.id.drawer_menu_external_links,
  757. MENU_ITEM_EXTERNAL_LINK + link.id, MENU_ORDER_EXTERNAL_LINKS, link.name)
  758. .setCheckable(true).getItemId();
  759. MenuSimpleTarget target = new MenuSimpleTarget<Drawable>(id) {
  760. @Override
  761. public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) {
  762. setExternalLinkIcon(getIdMenuItem(), resource, greyColor);
  763. }
  764. @Override
  765. public void onLoadFailed(Exception e, Drawable errorDrawable) {
  766. super.onLoadFailed(e, errorDrawable);
  767. setExternalLinkIcon(getIdMenuItem(), errorDrawable, greyColor);
  768. }
  769. };
  770. DisplayUtils.downloadIcon(getUserAccountManager(),
  771. clientFactory,
  772. this,
  773. link.iconUrl,
  774. target,
  775. R.drawable.ic_link,
  776. size,
  777. size);
  778. }
  779. setDrawerMenuItemChecked(mCheckedMenuItem);
  780. }
  781. }
  782. private void setExternalLinkIcon(int id, Drawable drawable, int greyColor) {
  783. MenuItem menuItem = mNavigationView.getMenu().findItem(id);
  784. if (menuItem != null) {
  785. if (drawable != null) {
  786. menuItem.setIcon(ThemeDrawableUtils.tintDrawable(drawable, greyColor));
  787. } else {
  788. menuItem.setIcon(R.drawable.ic_link);
  789. }
  790. }
  791. }
  792. @Override
  793. protected void onCreate(Bundle savedInstanceState) {
  794. super.onCreate(savedInstanceState);
  795. if (savedInstanceState != null) {
  796. mIsAccountChooserActive = savedInstanceState.getBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, false);
  797. mCheckedMenuItem = savedInstanceState.getInt(KEY_CHECKED_MENU_ITEM, Menu.NONE);
  798. }
  799. externalLinksProvider = new ExternalLinksProvider(getContentResolver());
  800. arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
  801. }
  802. @Override
  803. protected void onSaveInstanceState(@NonNull Bundle outState) {
  804. super.onSaveInstanceState(outState);
  805. outState.putBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, mIsAccountChooserActive);
  806. outState.putInt(KEY_CHECKED_MENU_ITEM, mCheckedMenuItem);
  807. }
  808. @Override
  809. public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
  810. super.onRestoreInstanceState(savedInstanceState);
  811. mIsAccountChooserActive = savedInstanceState.getBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, false);
  812. mCheckedMenuItem = savedInstanceState.getInt(KEY_CHECKED_MENU_ITEM, Menu.NONE);
  813. // check/highlight the menu item if present
  814. if (mCheckedMenuItem > Menu.NONE || mCheckedMenuItem < Menu.NONE) {
  815. setDrawerMenuItemChecked(mCheckedMenuItem);
  816. }
  817. }
  818. @Override
  819. protected void onPostCreate(Bundle savedInstanceState) {
  820. super.onPostCreate(savedInstanceState);
  821. // Sync the toggle state after onRestoreInstanceState has occurred.
  822. if (mDrawerToggle != null) {
  823. mDrawerToggle.syncState();
  824. if (isDrawerOpen()) {
  825. mDrawerToggle.setDrawerIndicatorEnabled(true);
  826. }
  827. }
  828. updateExternalLinksInDrawer();
  829. updateQuotaLink();
  830. }
  831. @Override
  832. public void onConfigurationChanged(@NonNull Configuration newConfig) {
  833. super.onConfigurationChanged(newConfig);
  834. if (mDrawerToggle != null) {
  835. mDrawerToggle.onConfigurationChanged(newConfig);
  836. }
  837. }
  838. @Override
  839. public void onBackPressed() {
  840. if (isDrawerOpen()) {
  841. closeDrawer();
  842. return;
  843. }
  844. Fragment fileDetailsSharingProcessFragment =
  845. getSupportFragmentManager().findFragmentByTag(FileDetailsSharingProcessFragment.TAG);
  846. if (fileDetailsSharingProcessFragment != null) {
  847. ((FileDetailsSharingProcessFragment)fileDetailsSharingProcessFragment).onBackPressed();
  848. } else {
  849. super.onBackPressed();
  850. }
  851. }
  852. @Override
  853. protected void onResume() {
  854. super.onResume();
  855. setDrawerMenuItemChecked(mCheckedMenuItem);
  856. }
  857. @Override
  858. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  859. super.onActivityResult(requestCode, resultCode, data);
  860. // update Account list and active account if Manage Account activity replies with
  861. // - ACCOUNT_LIST_CHANGED = true
  862. // - RESULT_OK
  863. if (requestCode == ACTION_MANAGE_ACCOUNTS && resultCode == RESULT_OK
  864. && data.getBooleanExtra(ManageAccountsActivity.KEY_ACCOUNT_LIST_CHANGED, false)) {
  865. // current account has changed
  866. if (data.getBooleanExtra(ManageAccountsActivity.KEY_CURRENT_ACCOUNT_CHANGED, false)) {
  867. setAccount(accountManager.getCurrentAccount(), false);
  868. restart();
  869. }
  870. } else if (requestCode == PassCodeManager.PASSCODE_ACTIVITY && data != null) {
  871. int result = data.getIntExtra(RequestCredentialsActivity.KEY_CHECK_RESULT,
  872. RequestCredentialsActivity.KEY_CHECK_RESULT_FALSE);
  873. if (result == RequestCredentialsActivity.KEY_CHECK_RESULT_CANCEL) {
  874. Log_OC.d(TAG, "PassCodeManager cancelled");
  875. preferences.setLockTimestamp(0);
  876. finish();
  877. }
  878. }
  879. }
  880. /**
  881. * Quota view can be either at navigation bottom or header
  882. *
  883. * @param id the view's id
  884. * @return The view if found or <code>null</code> otherwise.
  885. */
  886. private View findQuotaViewById(int id) {
  887. View v = ((NavigationView) findViewById(R.id.nav_view)).getHeaderView(0).findViewById(id);
  888. if (v != null) {
  889. return v;
  890. } else {
  891. return findViewById(id);
  892. }
  893. }
  894. /**
  895. * restart helper method which is called after a changing the current account.
  896. */
  897. private void restart() {
  898. Intent i = new Intent(this, FileDisplayActivity.class);
  899. i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  900. i.setAction(FileDisplayActivity.RESTART);
  901. startActivity(i);
  902. fetchExternalLinks(false);
  903. }
  904. /**
  905. * show the file list to the user.
  906. *
  907. * @param onDeviceOnly flag to decide if all files or only the ones on the device should be shown
  908. */
  909. public void showFiles(boolean onDeviceOnly) {
  910. MainApp.showOnlyFilesOnDevice(onDeviceOnly);
  911. Intent fileDisplayActivity = new Intent(getApplicationContext(), FileDisplayActivity.class);
  912. fileDisplayActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  913. startActivity(fileDisplayActivity);
  914. }
  915. @Override
  916. public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
  917. if (callContext instanceof MenuItem) {
  918. MenuItem menuItem = (MenuItem) callContext;
  919. menuItem.setIcon(avatarDrawable);
  920. } else if (callContext instanceof ImageView) {
  921. ImageView imageView = (ImageView) callContext;
  922. imageView.setImageDrawable(avatarDrawable);
  923. } else if (callContext instanceof MaterialButton) {
  924. MaterialButton materialButton = (MaterialButton) callContext;
  925. materialButton.setIcon(avatarDrawable);
  926. }
  927. }
  928. @Override
  929. public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
  930. if (callContext instanceof MenuItem) {
  931. MenuItem menuItem = (MenuItem) callContext;
  932. return String.valueOf(menuItem.getTitle()).equals(tag);
  933. } else if (callContext instanceof ImageView) {
  934. ImageView imageView = (ImageView) callContext;
  935. return String.valueOf(imageView.getTag()).equals(tag);
  936. } else if (callContext instanceof MaterialButton) {
  937. MaterialButton materialButton = (MaterialButton) callContext;
  938. return String.valueOf(materialButton.getTag()).equals(tag);
  939. }
  940. return false;
  941. }
  942. /**
  943. * Adds other listeners to react on changes of the drawer layout.
  944. *
  945. * @param listener Object interested in changes of the drawer layout.
  946. */
  947. public void addDrawerListener(DrawerLayout.DrawerListener listener) {
  948. if (mDrawerLayout != null) {
  949. mDrawerLayout.addDrawerListener(listener);
  950. } else {
  951. Log_OC.e(TAG, "Drawer layout not ready to add drawer listener");
  952. }
  953. }
  954. public boolean isDrawerIndicatorAvailable() {
  955. return true;
  956. }
  957. @Override
  958. protected void onStart() {
  959. super.onStart();
  960. EventBus.getDefault().register(this);
  961. }
  962. @Override
  963. protected void onStop() {
  964. if (preferences.getLockTimestamp() != 0) {
  965. preferences.setLockTimestamp(SystemClock.elapsedRealtime());
  966. }
  967. EventBus.getDefault().unregister(this);
  968. super.onStop();
  969. }
  970. @Subscribe(threadMode = ThreadMode.MAIN)
  971. public void onAccountRemovedEvent(AccountRemovedEvent event) {
  972. restart();
  973. }
  974. /**
  975. * Retrieves external links via api from 'external' app
  976. */
  977. public void fetchExternalLinks(final boolean force) {
  978. if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
  979. Thread t = new Thread(() -> {
  980. // fetch capabilities as early as possible
  981. if ((getCapabilities() == null || getCapabilities().getAccountName().isEmpty())
  982. && getStorageManager() != null) {
  983. GetCapabilitiesOperation getCapabilities = new GetCapabilitiesOperation(getStorageManager());
  984. getCapabilities.execute(getBaseContext());
  985. }
  986. User user = accountManager.getUser();
  987. String name = user.getAccountName();
  988. if (getStorageManager() != null && getStorageManager().getCapability(name).getExternalLinks().isTrue()) {
  989. int count = arbitraryDataProvider.getIntegerValue(FilesSyncHelper.GLOBAL,
  990. FileActivity.APP_OPENED_COUNT);
  991. if (count > 10 || count == -1 || force) {
  992. if (force) {
  993. Log_OC.d("ExternalLinks", "force update");
  994. }
  995. arbitraryDataProvider.storeOrUpdateKeyValue(FilesSyncHelper.GLOBAL,
  996. FileActivity.APP_OPENED_COUNT, "0");
  997. Log_OC.d("ExternalLinks", "update via api");
  998. RemoteOperation getExternalLinksOperation = new ExternalLinksOperation();
  999. RemoteOperationResult result = getExternalLinksOperation.execute(user.toPlatformAccount(), this);
  1000. if (result.isSuccess() && result.getData() != null) {
  1001. externalLinksProvider.deleteAllExternalLinks();
  1002. ArrayList<ExternalLink> externalLinks = (ArrayList<ExternalLink>) (Object) result.getData();
  1003. for (ExternalLink link : externalLinks) {
  1004. externalLinksProvider.storeExternalLink(link);
  1005. }
  1006. }
  1007. } else {
  1008. arbitraryDataProvider.storeOrUpdateKeyValue(FilesSyncHelper.GLOBAL,
  1009. FileActivity.APP_OPENED_COUNT, String.valueOf(count + 1));
  1010. }
  1011. } else {
  1012. externalLinksProvider.deleteAllExternalLinks();
  1013. Log_OC.d("ExternalLinks", "links disabled");
  1014. }
  1015. runOnUiThread(this::updateExternalLinksInDrawer);
  1016. });
  1017. t.start();
  1018. }
  1019. }
  1020. }