3 |
efrain |
1 |
package com.cesams.leaderslinked.v2;
|
|
|
2 |
|
|
|
3 |
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
|
|
4 |
|
|
|
5 |
import android.Manifest;
|
|
|
6 |
|
|
|
7 |
import androidx.activity.result.ActivityResultLauncher;
|
|
|
8 |
import androidx.activity.result.contract.ActivityResultContracts;
|
|
|
9 |
import androidx.annotation.NonNull;
|
|
|
10 |
import androidx.annotation.Nullable;
|
|
|
11 |
import androidx.annotation.RequiresApi;
|
|
|
12 |
import androidx.appcompat.app.AppCompatActivity;
|
|
|
13 |
import androidx.core.app.ActivityCompat;
|
|
|
14 |
import androidx.core.content.ContextCompat;
|
|
|
15 |
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
|
16 |
import androidx.core.view.ViewCompat;
|
|
|
17 |
import androidx.core.view.WindowInsetsCompat;
|
|
|
18 |
|
|
|
19 |
|
|
|
20 |
import android.content.pm.PackageManager;
|
|
|
21 |
import android.annotation.SuppressLint;
|
|
|
22 |
import android.content.Intent;
|
|
|
23 |
import android.content.res.Configuration;
|
5 |
efrain |
24 |
import android.net.ConnectivityManager;
|
|
|
25 |
import android.net.NetworkInfo;
|
3 |
efrain |
26 |
import android.net.Uri;
|
|
|
27 |
import android.os.Build;
|
|
|
28 |
import android.os.Bundle;
|
|
|
29 |
import android.util.Log;
|
|
|
30 |
import android.view.KeyEvent;
|
|
|
31 |
import android.view.View;
|
|
|
32 |
import android.webkit.JavascriptInterface;
|
|
|
33 |
import android.webkit.ValueCallback;
|
|
|
34 |
import android.webkit.WebChromeClient;
|
|
|
35 |
import android.webkit.WebSettings;
|
|
|
36 |
import android.webkit.WebView;
|
|
|
37 |
import android.webkit.WebViewClient;
|
|
|
38 |
|
|
|
39 |
import java.util.ArrayList;
|
|
|
40 |
|
|
|
41 |
public class MainActivity extends AppCompatActivity {
|
|
|
42 |
private TouchyWebView mWebView = null;
|
|
|
43 |
private SwipeRefreshLayout mSwipeRefreshLayout;
|
10 |
efrain |
44 |
private static final String file_type = "*/*";
|
3 |
efrain |
45 |
private ValueCallback<Uri[]> file_path;
|
10 |
efrain |
46 |
private final static String _URL = BuildConfig.BASE_URL;
|
3 |
efrain |
47 |
private ActivityResultLauncher<Intent> fileChooserLauncher;
|
|
|
48 |
|
|
|
49 |
@RequiresApi(api = Build.VERSION_CODES.M)
|
|
|
50 |
@Override
|
|
|
51 |
protected void onCreate(Bundle savedInstanceState) {
|
|
|
52 |
super.onCreate(savedInstanceState);
|
|
|
53 |
setContentView(R.layout.activity_main);
|
|
|
54 |
|
|
|
55 |
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.swipeRefreshLayout), (v, insets) -> {
|
|
|
56 |
int top = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top;
|
|
|
57 |
int bottom = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
|
|
|
58 |
int left = insets.getInsets(WindowInsetsCompat.Type.systemBars()).left;
|
|
|
59 |
int right = insets.getInsets(WindowInsetsCompat.Type.systemBars()).right;
|
|
|
60 |
|
|
|
61 |
v.setPadding(left, top, right, bottom);
|
|
|
62 |
|
|
|
63 |
return insets;
|
|
|
64 |
});
|
|
|
65 |
|
|
|
66 |
|
|
|
67 |
fileChooserLauncher = registerForActivityResult(
|
|
|
68 |
new ActivityResultContracts.StartActivityForResult(),
|
|
|
69 |
result -> {
|
10 |
efrain |
70 |
// Para selección de archivos de galería
|
|
|
71 |
if (file_path == null) {
|
|
|
72 |
return;
|
3 |
efrain |
73 |
}
|
10 |
efrain |
74 |
Uri[] uris = WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), result.getData());
|
|
|
75 |
file_path.onReceiveValue(uris);
|
|
|
76 |
file_path = null;
|
3 |
efrain |
77 |
});
|
|
|
78 |
|
10 |
efrain |
79 |
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
|
3 |
efrain |
80 |
|
|
|
81 |
mSwipeRefreshLayout.setOnChildScrollUpCallback(new SwipeRefreshLayout.OnChildScrollUpCallback() {
|
|
|
82 |
@Override
|
|
|
83 |
public boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child) {
|
|
|
84 |
return mWebView.canScrollVertically(-1);
|
|
|
85 |
}
|
|
|
86 |
});
|
|
|
87 |
|
|
|
88 |
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
|
|
89 |
@Override
|
|
|
90 |
public void onRefresh() {
|
|
|
91 |
mWebView.reload();
|
|
|
92 |
}
|
|
|
93 |
});
|
|
|
94 |
|
|
|
95 |
|
|
|
96 |
|
|
|
97 |
|
|
|
98 |
mWebView = (TouchyWebView) findViewById(R.id.webView);
|
|
|
99 |
|
5 |
efrain |
100 |
|
3 |
efrain |
101 |
// mWebView.setWebViewClient( mCesaWebViewClient);
|
|
|
102 |
|
|
|
103 |
mWebView.addJavascriptInterface(new JavaScriptShareInterface(), "AndroidShareHandler");
|
|
|
104 |
|
|
|
105 |
|
|
|
106 |
|
|
|
107 |
|
|
|
108 |
WebSettings webSettings = mWebView.getSettings();
|
|
|
109 |
webSettings.setJavaScriptEnabled(true);
|
|
|
110 |
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
|
|
|
111 |
webSettings.setAllowFileAccess(true);
|
|
|
112 |
webSettings.setAllowContentAccess(true);
|
|
|
113 |
webSettings.setAllowFileAccessFromFileURLs(true);
|
|
|
114 |
webSettings.setAllowUniversalAccessFromFileURLs(true);
|
|
|
115 |
webSettings.setDomStorageEnabled(true);
|
|
|
116 |
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
|
5 |
efrain |
117 |
webSettings.setDatabaseEnabled(false);
|
3 |
efrain |
118 |
webSettings.setDisplayZoomControls(true);
|
|
|
119 |
webSettings.setBuiltInZoomControls(true);
|
|
|
120 |
|
|
|
121 |
webSettings.setMediaPlaybackRequiresUserGesture(false);
|
|
|
122 |
|
|
|
123 |
|
|
|
124 |
mWebView.setWebViewClient(new WebViewClient() {
|
|
|
125 |
|
5 |
efrain |
126 |
@Override
|
|
|
127 |
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
|
|
128 |
super.onReceivedError(view, errorCode, description, failingUrl);
|
|
|
129 |
Log.e("WebView", "Error loading URL: " + failingUrl + " - " + description + " (Code: " + errorCode + ")");
|
|
|
130 |
|
|
|
131 |
// Intentar recargar una vez más después de un error
|
|
|
132 |
if (failingUrl.equals(_URL)) {
|
|
|
133 |
Log.d("WebView", "Attempting to reload after error...");
|
|
|
134 |
new android.os.Handler().postDelayed(new Runnable() {
|
|
|
135 |
@Override
|
|
|
136 |
public void run() {
|
|
|
137 |
view.reload();
|
|
|
138 |
}
|
|
|
139 |
}, 2000); // Esperar 2 segundos antes de reintentar
|
|
|
140 |
}
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
@Override
|
|
|
144 |
public void onReceivedSslError(WebView view, android.webkit.SslErrorHandler handler, android.net.http.SslError error) {
|
|
|
145 |
Log.e("WebView", "SSL Error: " + error.toString() + " for URL: " + error.getUrl());
|
|
|
146 |
// Continuar a pesar del error SSL (solo para desarrollo/testing)
|
|
|
147 |
handler.proceed();
|
|
|
148 |
}
|
3 |
efrain |
149 |
|
5 |
efrain |
150 |
@Override
|
|
|
151 |
public void onPageStarted(WebView view, String url, android.graphics.Bitmap favicon) {
|
|
|
152 |
super.onPageStarted(view, url, favicon);
|
|
|
153 |
Log.d("WebView", "Started loading: " + url);
|
|
|
154 |
mSwipeRefreshLayout.setRefreshing(true);
|
|
|
155 |
}
|
3 |
efrain |
156 |
|
|
|
157 |
@Override
|
|
|
158 |
public void onPageFinished(WebView view, String url) {
|
|
|
159 |
findViewById(R.id.webView).setVisibility(View.VISIBLE);
|
|
|
160 |
mSwipeRefreshLayout.setRefreshing(false);
|
5 |
efrain |
161 |
Log.d("WebView", "Finished loading: " + url);
|
3 |
efrain |
162 |
}
|
|
|
163 |
|
|
|
164 |
@Override
|
|
|
165 |
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
|
|
166 |
if(url.contains("leaderslinked.com") ) return false;
|
|
|
167 |
|
|
|
168 |
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
|
|
169 |
MainActivity.this.startActivity(intent);
|
|
|
170 |
return true;
|
|
|
171 |
}
|
|
|
172 |
|
|
|
173 |
});
|
|
|
174 |
|
|
|
175 |
mWebView.setWebChromeClient(new WebChromeClient()
|
|
|
176 |
{
|
|
|
177 |
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
|
|
|
178 |
|
10 |
efrain |
179 |
if(file_permission()) {
|
3 |
efrain |
180 |
file_path = filePathCallback;
|
|
|
181 |
|
10 |
efrain |
182 |
// Solo permitir selección de galería/archivos
|
3 |
efrain |
183 |
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
|
184 |
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
|
185 |
contentSelectionIntent.setType(file_type);
|
10 |
efrain |
186 |
contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
3 |
efrain |
187 |
|
|
|
188 |
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
|
|
189 |
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
10 |
efrain |
190 |
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Seleccionar archivo");
|
|
|
191 |
|
3 |
efrain |
192 |
fileChooserLauncher.launch(chooserIntent);
|
|
|
193 |
return true;
|
|
|
194 |
} else {
|
|
|
195 |
return false;
|
|
|
196 |
}
|
|
|
197 |
}
|
|
|
198 |
});
|
|
|
199 |
|
10 |
efrain |
200 |
// Verify network connection
|
5 |
efrain |
201 |
if (isNetworkAvailable()) {
|
|
|
202 |
Log.d("WebView", "Network available, proceeding to load URL");
|
10 |
efrain |
203 |
// Clear cache before load
|
5 |
efrain |
204 |
clearWebViewCache();
|
|
|
205 |
mWebView.loadUrl(_URL);
|
10 |
efrain |
206 |
} else {
|
5 |
efrain |
207 |
Log.e("WebView", "No network connection available");
|
|
|
208 |
}
|
3 |
efrain |
209 |
}
|
5 |
efrain |
210 |
|
|
|
211 |
private void clearWebViewCache() {
|
|
|
212 |
// Limpiar todos los tipos de caché del WebView
|
|
|
213 |
mWebView.clearCache(true);
|
|
|
214 |
mWebView.clearFormData();
|
|
|
215 |
mWebView.clearHistory();
|
|
|
216 |
mWebView.clearSslPreferences();
|
|
|
217 |
|
10 |
efrain |
218 |
// Clear cookies
|
|
|
219 |
android.webkit.CookieManager.getInstance().removeAllCookies(null);
|
|
|
220 |
android.webkit.CookieManager.getInstance().flush();
|
|
|
221 |
|
5 |
efrain |
222 |
Log.d("WebView", "Cache, cookies and data cleared completely");
|
3 |
efrain |
223 |
}
|
5 |
efrain |
224 |
|
|
|
225 |
private boolean isNetworkAvailable() {
|
|
|
226 |
ConnectivityManager connectivityManager =
|
|
|
227 |
(ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
|
|
|
228 |
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
|
|
229 |
boolean isConnected = activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
|
|
230 |
Log.d("WebView", "Network status: " + (isConnected ? "Connected" : "Disconnected"));
|
|
|
231 |
return isConnected;
|
|
|
232 |
}
|
3 |
efrain |
233 |
|
|
|
234 |
@Override
|
|
|
235 |
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
|
236 |
if ((keyCode == KeyEvent.KEYCODE_BACK) && this.mWebView.canGoBack()) {
|
|
|
237 |
this.mWebView.goBack();
|
|
|
238 |
return true;
|
|
|
239 |
}
|
|
|
240 |
|
|
|
241 |
return super.onKeyDown(keyCode, event);
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
|
|
|
245 |
|
|
|
246 |
|
|
|
247 |
@Override
|
|
|
248 |
protected void onSaveInstanceState(Bundle outState){
|
|
|
249 |
super.onSaveInstanceState(outState);
|
|
|
250 |
|
|
|
251 |
// Save the state of the WebView
|
|
|
252 |
mWebView.saveState(outState);
|
|
|
253 |
}
|
|
|
254 |
|
|
|
255 |
@Override
|
|
|
256 |
protected void onRestoreInstanceState(Bundle savedInstanceState){
|
|
|
257 |
super.onRestoreInstanceState(savedInstanceState);
|
|
|
258 |
|
|
|
259 |
// Restore the state of the WebView
|
|
|
260 |
mWebView.restoreState(savedInstanceState);
|
|
|
261 |
}
|
|
|
262 |
|
|
|
263 |
@Override
|
|
|
264 |
public void onConfigurationChanged(Configuration newConfig){
|
|
|
265 |
super.onConfigurationChanged(newConfig);
|
|
|
266 |
}
|
|
|
267 |
|
|
|
268 |
public boolean file_permission(){
|
|
|
269 |
int checkPermissionExternal = PackageManager.PERMISSION_GRANTED;
|
|
|
270 |
int checkPermissionReadMediaAudio = PackageManager.PERMISSION_GRANTED;
|
|
|
271 |
int checkPermissionReadMediaVideo = PackageManager.PERMISSION_GRANTED;
|
|
|
272 |
int checkPermissionReadMediaImages = PackageManager.PERMISSION_GRANTED;
|
|
|
273 |
|
|
|
274 |
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
|
275 |
checkPermissionExternal = ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE);
|
|
|
276 |
} else {
|
|
|
277 |
checkPermissionReadMediaAudio = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO);
|
|
|
278 |
checkPermissionReadMediaVideo = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_VIDEO);
|
|
|
279 |
checkPermissionReadMediaImages = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES);
|
|
|
280 |
}
|
|
|
281 |
|
|
|
282 |
|
10 |
efrain |
283 |
boolean ok = true;
|
3 |
efrain |
284 |
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
10 |
efrain |
285 |
ok = checkPermissionExternal == PackageManager.PERMISSION_GRANTED;
|
3 |
efrain |
286 |
} else {
|
10 |
efrain |
287 |
ok = checkPermissionReadMediaAudio == PackageManager.PERMISSION_GRANTED;
|
3 |
efrain |
288 |
ok = ok && checkPermissionReadMediaVideo == PackageManager.PERMISSION_GRANTED;
|
|
|
289 |
ok = ok && checkPermissionReadMediaImages == PackageManager.PERMISSION_GRANTED;
|
|
|
290 |
}
|
|
|
291 |
|
|
|
292 |
if(!ok) {
|
|
|
293 |
|
|
|
294 |
ArrayList<String> newPermissionList = new ArrayList<>();
|
|
|
295 |
|
|
|
296 |
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
|
297 |
if(checkPermissionExternal != PackageManager.PERMISSION_GRANTED) {
|
|
|
298 |
newPermissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
|
|
299 |
}
|
|
|
300 |
} else {
|
|
|
301 |
if(checkPermissionReadMediaAudio != PackageManager.PERMISSION_GRANTED) {
|
|
|
302 |
newPermissionList.add(Manifest.permission.READ_MEDIA_AUDIO);
|
|
|
303 |
}
|
|
|
304 |
if(checkPermissionReadMediaVideo != PackageManager.PERMISSION_GRANTED) {
|
|
|
305 |
newPermissionList.add(Manifest.permission.READ_MEDIA_VIDEO);
|
|
|
306 |
}
|
|
|
307 |
if(checkPermissionReadMediaImages != PackageManager.PERMISSION_GRANTED) {
|
|
|
308 |
newPermissionList.add(Manifest.permission.READ_MEDIA_IMAGES);
|
|
|
309 |
}
|
|
|
310 |
}
|
|
|
311 |
|
|
|
312 |
|
|
|
313 |
|
|
|
314 |
|
|
|
315 |
String permissions[] = newPermissionList.toArray(new String[newPermissionList.size()]);
|
|
|
316 |
ActivityCompat.requestPermissions(MainActivity.this, permissions, 1);
|
10 |
efrain |
317 |
return false; // No abrir selector hasta que se concedan permisos
|
3 |
efrain |
318 |
} else {
|
10 |
efrain |
319 |
return true; // Permisos concedidos, permitir abrir selector
|
3 |
efrain |
320 |
}
|
|
|
321 |
}
|
|
|
322 |
|
10 |
efrain |
323 |
@Override
|
|
|
324 |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
|
325 |
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
|
326 |
|
|
|
327 |
if (requestCode == 1) {
|
|
|
328 |
boolean allPermissionsGranted = true;
|
|
|
329 |
for (int result : grantResults) {
|
|
|
330 |
if (result != PackageManager.PERMISSION_GRANTED) {
|
|
|
331 |
allPermissionsGranted = false;
|
|
|
332 |
break;
|
|
|
333 |
}
|
|
|
334 |
}
|
|
|
335 |
|
|
|
336 |
if (allPermissionsGranted) {
|
|
|
337 |
Log.d("MainActivity", "Todos los permisos han sido concedidos");
|
|
|
338 |
// Los permisos han sido concedidos, el usuario puede intentar nuevamente abrir el selector
|
|
|
339 |
} else {
|
|
|
340 |
Log.d("MainActivity", "Algunos permisos fueron denegados");
|
|
|
341 |
// Algunos permisos fueron denegados
|
|
|
342 |
}
|
|
|
343 |
}
|
3 |
efrain |
344 |
}
|
|
|
345 |
|
|
|
346 |
|
|
|
347 |
|
|
|
348 |
private class JavaScriptShareInterface {
|
|
|
349 |
|
|
|
350 |
|
|
|
351 |
@JavascriptInterface
|
|
|
352 |
public void share(String url, String title, String content) {
|
|
|
353 |
try {
|
|
|
354 |
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
|
|
355 |
shareIntent.setType("text/plain");
|
|
|
356 |
shareIntent.putExtra(Intent.EXTRA_SUBJECT, title);
|
|
|
357 |
String shareMessage= "\n" + content + "\n\n";
|
|
|
358 |
shareMessage = shareMessage + url +"\n\n";
|
|
|
359 |
shareIntent.putExtra(Intent.EXTRA_TEXT, shareMessage);
|
|
|
360 |
|
|
|
361 |
Intent chooserIntent = Intent.createChooser(shareIntent, "choose one");
|
|
|
362 |
|
|
|
363 |
startActivity(chooserIntent);
|
|
|
364 |
} catch(Exception e) {
|
|
|
365 |
//e.toString();
|
|
|
366 |
}
|
|
|
367 |
}
|
|
|
368 |
|
|
|
369 |
}
|
|
|
370 |
}
|