FreeRDP
Loading...
Searching...
No Matches
HomeActivity.java
1/*
2 Main/Home Activity
3
4 Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
5 Copyright 2026 Ibrahim Sevinc <ibrahim.sevinc.mail@gmail.com>
6
7 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
8 If a copy of the MPL was not distributed with this file, You can obtain one at
9 http://mozilla.org/MPL/2.0/.
10*/
11
12package com.freerdp.freerdpcore.presentation;
13
14import androidx.appcompat.app.AlertDialog;
15import android.Manifest;
16import android.content.Intent;
17import android.content.pm.PackageManager;
18import android.net.Uri;
19import android.os.Build;
20import android.os.Bundle;
21import android.widget.Toast;
22import androidx.appcompat.app.AppCompatActivity;
23import androidx.core.content.FileProvider;
24import android.util.Log;
25import android.view.Menu;
26import android.view.MenuInflater;
27import android.view.MenuItem;
28
29import androidx.activity.OnBackPressedCallback;
30import androidx.appcompat.widget.SearchView;
31import androidx.lifecycle.ViewModelProvider;
32import androidx.recyclerview.widget.LinearLayoutManager;
33
34import com.freerdp.freerdpcore.R;
35import com.freerdp.freerdpcore.databinding.HomeBinding;
36import com.freerdp.freerdpcore.domain.BookmarkBase;
37import com.freerdp.freerdpcore.domain.ConnectionReference;
38import com.freerdp.freerdpcore.utils.BookmarkListAdapter;
39import com.freerdp.freerdpcore.utils.RDPFileHelper;
40
41import java.io.File;
42import java.io.FileOutputStream;
43import java.io.IOException;
44import java.nio.charset.StandardCharsets;
45
46public class HomeActivity extends AppCompatActivity
47{
48 private static final String TAG = "HomeActivity";
49 private static final String PARAM_SEARCH_QUERY = "search_query";
50
51 private HomeBinding binding;
52 private HomeViewModel viewModel;
53 private BookmarkListAdapter bookmarkListAdapter;
54 private MenuItem searchMenuItem;
55 private SearchView searchView;
56
57 private ExternalDisplayManager externalDisplayManager;
58
59 @Override public void onCreate(Bundle savedInstanceState)
60 {
61 super.onCreate(savedInstanceState);
62 binding = HomeBinding.inflate(getLayoutInflater());
63 setContentView(binding.getRoot());
64
65 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
66 checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) !=
67 PackageManager.PERMISSION_GRANTED)
68 {
69 requestPermissions(new String[] { Manifest.permission.POST_NOTIFICATIONS }, 0);
70 }
71
72 externalDisplayManager = new ExternalDisplayManager(this);
73
74 long heapSize = Runtime.getRuntime().maxMemory();
75 Log.i(TAG, "Max HeapSize: " + heapSize);
76 Log.i(TAG, "App data folder: " + getFilesDir().toString());
77
78 // check for passed .rdp file and open it in a new bookmark
79 Intent caller = getIntent();
80 Uri callParameter = caller.getData();
81
82 if (Intent.ACTION_VIEW.equals(caller.getAction()) && callParameter != null)
83 {
84 String refStr = ConnectionReference.getFileReference(callParameter.toString());
85 Bundle bundle = new Bundle();
86 bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr);
87
88 Intent bookmarkIntent =
89 new Intent(this.getApplicationContext(), BookmarkActivity.class);
90 bookmarkIntent.putExtras(bundle);
91 startActivity(bookmarkIntent);
92 }
93
94 viewModel = new ViewModelProvider(this).get(HomeViewModel.class);
95
96 bookmarkListAdapter = new BookmarkListAdapter();
97 bookmarkListAdapter.setCallbacks(new BookmarkListAdapter.Callbacks() {
98 @Override public void onItemClick(String refStr)
99 {
100 if (ConnectionReference.isBookmarkReference(refStr) ||
101 ConnectionReference.isHostnameReference(refStr))
102 {
103 externalDisplayManager.launchSessionWithDisplayPicker(refStr);
104
105 if (searchView != null)
106 {
107 searchView.setQuery("", false);
108 searchView.setIconified(true);
109 }
110 if (searchMenuItem != null)
111 {
112 searchMenuItem.collapseActionView();
113 }
114 viewModel.loadBookmarks("");
115 }
116 }
117
118 @Override public void onDelete(long id)
119 {
120 viewModel.deleteBookmark(id);
121 }
122
123 @Override public void onExport(BookmarkBase bookmark)
124 {
125 shareRdpFile(bookmark);
126 }
127 });
128
129 binding.recyclerViewBookmarks.setLayoutManager(new LinearLayoutManager(this));
130 binding.recyclerViewBookmarks.setAdapter(bookmarkListAdapter);
131
132 viewModel.getBookmarks().observe(this,
133 bookmarks -> bookmarkListAdapter.setItems(bookmarks));
134
135 // restore search query after process death
136 if (savedInstanceState != null)
137 {
138 String query = savedInstanceState.getString(PARAM_SEARCH_QUERY);
139 if (query != null && !query.isEmpty() && viewModel.getCurrentQuery().isEmpty())
140 {
141 viewModel.loadBookmarks(query);
142 }
143 }
144
145 getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
146 @Override public void handleOnBackPressed()
147 {
148 if (ApplicationSettingsActivity.getAskOnExit(HomeActivity.this))
149 {
150 new AlertDialog.Builder(HomeActivity.this)
151 .setTitle(R.string.dlg_title_exit)
152 .setMessage(R.string.dlg_msg_exit)
153 .setPositiveButton(R.string.yes, (dialog, which) -> finish())
154 .setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss())
155 .show();
156 }
157 else
158 {
159 finish();
160 }
161 }
162 });
163 }
164
165 @Override protected void onResume()
166 {
167 super.onResume();
168 Log.v(TAG, "HomeActivity.onResume");
169 viewModel.loadBookmarks(viewModel.getCurrentQuery());
170 }
171
172 @Override protected void onSaveInstanceState(Bundle outState)
173 {
174 super.onSaveInstanceState(outState);
175 outState.putString(PARAM_SEARCH_QUERY, viewModel.getCurrentQuery());
176 }
177
178 @Override public boolean onCreateOptionsMenu(Menu menu)
179 {
180 MenuInflater inflater = getMenuInflater();
181 inflater.inflate(R.menu.home_menu, menu);
182 setupSearchView(menu);
183 return true;
184 }
185
186 @Override public boolean onOptionsItemSelected(MenuItem item)
187 {
188 // refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case
189 // here ..
190 int itemId = item.getItemId();
191 if (itemId == R.id.newBookmark)
192 {
193 Intent bookmarkIntent = new Intent(this, BookmarkActivity.class);
194 startActivity(bookmarkIntent);
195 }
196 else if (itemId == R.id.appSettings)
197 {
198 Intent settingsIntent = new Intent(this, ApplicationSettingsActivity.class);
199 startActivity(settingsIntent);
200 }
201 else if (itemId == R.id.help)
202 {
203 Intent helpIntent = new Intent(this, HelpActivity.class);
204 startActivity(helpIntent);
205 }
206 else if (itemId == R.id.about)
207 {
208 Intent aboutIntent = new Intent(this, AboutActivity.class);
209 startActivity(aboutIntent);
210 }
211
212 return true;
213 }
214
215 private void shareRdpFile(BookmarkBase bookmark)
216 {
217 String filename = bookmark.getLabel().replaceAll("[^\\w. -]", "_") + ".rdp";
218 File file = new File(getCacheDir(), filename);
219 try (FileOutputStream out = new FileOutputStream(file))
220 {
221 out.write(RDPFileHelper.toRdpString(bookmark).getBytes(StandardCharsets.UTF_8));
222 }
223 catch (IOException e)
224 {
225 Log.e(TAG, "Failed to write RDP file for sharing", e);
226 Toast.makeText(this, R.string.export_failed, Toast.LENGTH_SHORT).show();
227 return;
228 }
229 Uri uri = FileProvider.getUriForFile(this, "com.freerdp.afreerdp.fileprovider", file);
230 Intent share = new Intent(Intent.ACTION_SEND);
231 share.setType("application/x-rdp");
232 share.putExtra(Intent.EXTRA_STREAM, uri);
233 share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
234 startActivity(Intent.createChooser(share, bookmark.getLabel()));
235 }
236
237 private void setupSearchView(Menu menu)
238 {
239 searchMenuItem = menu.findItem(R.id.action_search);
240 if (searchMenuItem != null)
241 {
242 searchView = (SearchView)searchMenuItem.getActionView();
243
244 String currentQuery = viewModel.getCurrentQuery();
245 if (currentQuery != null && !currentQuery.isEmpty())
246 {
247 searchMenuItem.expandActionView();
248 searchView.setQuery(currentQuery, false);
249 searchView.clearFocus();
250 }
251
252 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
253 @Override public boolean onQueryTextSubmit(String query)
254 {
255 return true;
256 }
257
258 @Override public boolean onQueryTextChange(String s)
259 {
260 viewModel.loadBookmarks(s);
261 return true;
262 }
263 });
264 }
265 }
266}