Этот коммит содержится в:
Anton Tananaev
2021-07-18 12:04:45 -07:00
родитель 3b399c41ad
Коммит a983b26480
10 изменённых файлов: 420 добавлений и 466 удалений
+2 -1
Просмотреть файл
@@ -29,11 +29,12 @@ android {
dependencies { dependencies {
implementation 'com.google.android.material:material:1.4.0' implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.preference:preference-ktx:1.1.1'
googleImplementation 'com.google.firebase:firebase-core:19.0.0' googleImplementation 'com.google.firebase:firebase-core:19.0.0'
googleImplementation 'com.google.firebase:firebase-analytics:19.0.0' googleImplementation 'com.google.firebase:firebase-analytics:19.0.0'
googleImplementation 'com.google.firebase:firebase-messaging:22.0.0' googleImplementation 'com.google.firebase:firebase-messaging:22.0.0'
googleImplementation 'com.google.firebase:firebase-crashlytics:18.1.0' googleImplementation 'com.google.firebase:firebase-crashlytics:18.1.0'
implementation "androidx.core:core-ktx:1.6.0" implementation 'androidx.core:core-ktx:1.6.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
} }
-70
Просмотреть файл
@@ -1,70 +0,0 @@
/*
* Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.manager;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
public class GoogleMainApplication extends Application {
private FirebaseAnalytics firebaseAnalytics;
@Override
public void onCreate() {
super.onCreate();
firebaseAnalytics = FirebaseAnalytics.getInstance(this);
IntentFilter intentFilter = new IntentFilter(MainFragment.EVENT_LOGIN);
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
getString(R.string.notification_channel_id), getString(R.string.notification_channel),
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
@Override
public void onSuccess(InstanceIdResult instanceIdResult) {
broadcastToken(instanceIdResult.getToken());
}
});
}
};
public void broadcastToken(String token) {
Intent intent = new Intent(MainFragment.EVENT_TOKEN);
intent.putExtra(MainFragment.KEY_TOKEN, token);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
+64
Просмотреть файл
@@ -0,0 +1,64 @@
/*
* Copyright 2017 - 2021 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.manager
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.messaging.FirebaseMessaging
class GoogleMainApplication : Application() {
private lateinit var firebaseAnalytics: FirebaseAnalytics
override fun onCreate() {
super.onCreate()
firebaseAnalytics = FirebaseAnalytics.getInstance(this)
val intentFilter = IntentFilter(MainFragment.EVENT_LOGIN)
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
getString(R.string.notification_channel_id),
getString(R.string.notification_channel),
NotificationManager.IMPORTANCE_DEFAULT
)
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
}
}
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
FirebaseMessaging.getInstance().token.addOnCompleteListener {
if (it.isComplete) {
broadcastToken(it.result)
}
}
}
}
fun broadcastToken(token: String?) {
val intent = Intent(MainFragment.EVENT_TOKEN)
intent.putExtra(MainFragment.KEY_TOKEN, token)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
}
-50
Просмотреть файл
@@ -1,50 +0,0 @@
/*
* Copyright 2018 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.manager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class ManagerMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
.setSmallIcon(R.drawable.ic_stat_notify)
.setContentTitle(getString(R.string.app_name))
.setContentText(remoteMessage.getNotification().getBody())
.setAutoCancel(true)
.setContentIntent(pendingIntent);;
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(remoteMessage.hashCode(), builder.build());
}
@Override
public void onNewToken(String token) {
super.onNewToken(token);
((GoogleMainApplication) getApplication()).broadcastToken(token);
}
}
+45
Просмотреть файл
@@ -0,0 +1,45 @@
/*
* Copyright 2018 - 2021 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.manager
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
class ManagerMessagingService : FirebaseMessagingService() {
@SuppressLint("UnspecifiedImmutableFlag")
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val pendingIntent = PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java), PendingIntent.FLAG_ONE_SHOT)
val builder = NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
.setSmallIcon(R.drawable.ic_stat_notify)
.setContentTitle(getString(R.string.app_name))
.setContentText(remoteMessage.notification?.body)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).notify(remoteMessage.hashCode(), builder.build())
}
override fun onNewToken(token: String) {
super.onNewToken(token)
(application as GoogleMainApplication).broadcastToken(token)
}
}
-56
Просмотреть файл
@@ -1,56 +0,0 @@
/*
* Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.manager;
import android.app.Fragment;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
public static final String PREFERENCE_URL = "url";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
initContent();
}
}
private void initContent() {
if (PreferenceManager.getDefaultSharedPreferences(this).contains(PREFERENCE_URL)) {
getFragmentManager().beginTransaction().add(android.R.id.content, new MainFragment()).commit();
} else {
getFragmentManager().beginTransaction().add(android.R.id.content, new StartFragment()).commit();
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content);
if (fragment != null) {
fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
+52
Просмотреть файл
@@ -0,0 +1,52 @@
/*
* Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("DEPRECATION")
package org.traccar.manager
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
initContent()
}
}
private fun initContent() {
if (PreferenceManager.getDefaultSharedPreferences(this).contains(PREFERENCE_URL)) {
fragmentManager.beginTransaction().add(android.R.id.content, MainFragment()).commit()
} else {
fragmentManager.beginTransaction().add(android.R.id.content, StartFragment()).commit()
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
val fragment = fragmentManager.findFragmentById(android.R.id.content)
fragment?.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
companion object {
const val PREFERENCE_URL = "url"
}
}
+134 -146
Просмотреть файл
@@ -13,206 +13,194 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.traccar.manager; @file:Suppress("DEPRECATION")
package org.traccar.manager
import android.Manifest; import android.Manifest
import android.annotation.SuppressLint; import android.annotation.SuppressLint
import android.app.Activity; import android.app.Activity
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver
import android.content.Context; import android.content.Context
import android.content.Intent; import android.content.DialogInterface
import android.content.IntentFilter; import android.content.Intent
import android.content.pm.ApplicationInfo; import android.content.IntentFilter
import android.content.pm.PackageManager; import android.content.pm.ApplicationInfo
import android.net.Uri; import android.content.pm.PackageManager
import android.os.Build; import android.net.Uri
import android.os.Bundle; import android.os.Build
import android.preference.PreferenceManager; import android.os.Bundle
import android.view.View; import android.view.View
import android.webkit.GeolocationPermissions; import android.webkit.GeolocationPermissions
import android.webkit.JavascriptInterface; import android.webkit.JavascriptInterface
import android.webkit.ValueCallback; import android.webkit.ValueCallback
import android.webkit.WebChromeClient; import android.webkit.WebChromeClient
import android.webkit.WebSettings; import android.webkit.WebView
import android.webkit.WebView; import android.webkit.WebViewFragment
import android.webkit.WebViewFragment; import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import androidx.annotation.NonNull; class MainFragment : WebViewFragment() {
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class MainFragment extends WebViewFragment { private lateinit var broadcastManager: LocalBroadcastManager
public final static String EVENT_LOGIN = "eventLogin";
public final static String EVENT_TOKEN = "eventToken";
public final static String KEY_TOKEN = "keyToken";
private static final int REQUEST_PERMISSIONS_LOCATION = 1;
private final static int REQUEST_FILE_CHOOSER = 1;
private LocalBroadcastManager broadcastManager;
public class AppInterface {
inner class AppInterface {
@JavascriptInterface @JavascriptInterface
public void postMessage(String message) { fun postMessage(message: String) {
if (message.contains("login")) { if (message.contains("login")) {
broadcastManager.sendBroadcast(new Intent(EVENT_LOGIN)); broadcastManager.sendBroadcast(Intent(EVENT_LOGIN))
} }
} }
} }
@Override override fun onCreate(savedInstanceState: Bundle?) {
public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState)
super.onCreate(savedInstanceState); broadcastManager = LocalBroadcastManager.getInstance(activity)
broadcastManager = LocalBroadcastManager.getInstance(getActivity());
} }
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState);
if ((getActivity().getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0) { if ((activity.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
WebView.setWebContentsDebuggingEnabled(true); WebView.setWebContentsDebuggingEnabled(true)
} }
webView.webChromeClient = webChromeClient
getWebView().setWebChromeClient(webChromeClient); webView.addJavascriptInterface(AppInterface(), "appInterface")
getWebView().addJavascriptInterface(new AppInterface(), "appInterface"); val webSettings = webView.settings
webSettings.javaScriptEnabled = true
WebSettings webSettings = getWebView().getSettings(); webSettings.domStorageEnabled = true
webSettings.setJavaScriptEnabled(true); webSettings.databaseEnabled = true
webSettings.setDomStorageEnabled(true); webSettings.mediaPlaybackRequiresUserGesture = false
webSettings.setDatabaseEnabled(true); val url = PreferenceManager.getDefaultSharedPreferences(activity)
webSettings.setMediaPlaybackRequiresUserGesture(false); .getString(MainActivity.PREFERENCE_URL, null)
url?.let { webView.loadUrl(it) }
String url = PreferenceManager.getDefaultSharedPreferences(
getActivity()).getString(MainActivity.PREFERENCE_URL, null);
getWebView().loadUrl(url);
} }
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
@Override override fun onReceive(context: Context, intent: Intent) {
public void onReceive(Context context, Intent intent) { val token = intent.getStringExtra(KEY_TOKEN)
String token = intent.getStringExtra(KEY_TOKEN); val code = "updateNotificationToken && updateNotificationToken('$token')"
String code = "updateNotificationToken && updateNotificationToken('" + token + "')"; webView.evaluateJavascript(code, null)
getWebView().evaluateJavascript(code, null);
} }
};
@Override
public void onStart() {
super.onStart();
IntentFilter intentFilter = new IntentFilter(EVENT_TOKEN);
broadcastManager.registerReceiver(broadcastReceiver, intentFilter);
} }
@Override override fun onStart() {
public void onStop() { super.onStart()
super.onStop(); val intentFilter = IntentFilter(EVENT_TOKEN)
broadcastManager.unregisterReceiver(broadcastReceiver); broadcastManager.registerReceiver(broadcastReceiver, intentFilter)
} }
private ValueCallback<Uri> openFileCallback; override fun onStop() {
private ValueCallback<Uri[]> openFileCallback2; super.onStop()
broadcastManager.unregisterReceiver(broadcastReceiver)
}
@Override private var openFileCallback: ValueCallback<Uri?>? = null
public void onActivityResult(int requestCode, int resultCode, Intent data) { private var openFileCallback2: ValueCallback<Array<Uri>>? = null
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_FILE_CHOOSER) { if (requestCode == REQUEST_FILE_CHOOSER) {
Uri result = data == null || resultCode != Activity.RESULT_OK ? null : data.getData(); val result = if (resultCode != Activity.RESULT_OK) null else data.data
if (openFileCallback != null) { if (openFileCallback != null) {
openFileCallback.onReceiveValue(result); openFileCallback?.onReceiveValue(result)
openFileCallback = null; openFileCallback = null
} }
if (openFileCallback2 != null) { if (openFileCallback2 != null) {
openFileCallback2.onReceiveValue(result != null ? new Uri[] { result } : new Uri[0]); openFileCallback2?.onReceiveValue(if (result != null) arrayOf(result) else arrayOf())
openFileCallback2 = null; openFileCallback2 = null
} }
} }
} }
@Override override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSIONS_LOCATION) { if (requestCode == REQUEST_PERMISSIONS_LOCATION) {
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; val granted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
if (geolocationCallback != null) { if (geolocationCallback != null) {
geolocationCallback.invoke(geolocationRequestOrigin, granted, false); geolocationCallback?.invoke(geolocationRequestOrigin, granted, false)
geolocationRequestOrigin = null; geolocationRequestOrigin = null
geolocationCallback = null; geolocationCallback = null
} }
} }
} }
private String geolocationRequestOrigin; private var geolocationRequestOrigin: String? = null
private GeolocationPermissions.Callback geolocationCallback; private var geolocationCallback: GeolocationPermissions.Callback? = null
private final WebChromeClient webChromeClient = new WebChromeClient() { private val webChromeClient: WebChromeClient = object : WebChromeClient() {
@Override override fun onGeolocationPermissionsShowPrompt(origin: String, callback: GeolocationPermissions.Callback) {
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { geolocationRequestOrigin = null
geolocationRequestOrigin = null; geolocationCallback = null
geolocationCallback = null; if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) { AlertDialog.Builder(activity)
new AlertDialog.Builder(getActivity()) .setMessage(R.string.permission_location_rationale)
.setMessage(R.string.permission_location_rationale) .setNeutralButton(android.R.string.ok) { dialog: DialogInterface?, which: Int ->
.setNeutralButton(android.R.string.ok, (dialog, which) -> { geolocationRequestOrigin = origin
geolocationRequestOrigin = origin; geolocationCallback = callback
geolocationCallback = callback; ActivityCompat.requestPermissions(
ActivityCompat.requestPermissions( activity,
getActivity(), new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, REQUEST_PERMISSIONS_LOCATION); arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
}) REQUEST_PERMISSIONS_LOCATION
.show(); )
}
.show()
} else { } else {
geolocationRequestOrigin = origin; geolocationRequestOrigin = origin
geolocationCallback = callback; geolocationCallback = callback
ActivityCompat.requestPermissions( ActivityCompat.requestPermissions(
getActivity(), new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, REQUEST_PERMISSIONS_LOCATION); activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_PERMISSIONS_LOCATION
)
} }
} else { } else {
callback.invoke(origin, true, false); callback.invoke(origin, true, false)
} }
} }
// Android 4.1+ // Android 4.1+
protected void openFileChooser(ValueCallback<Uri> uploadMessage, String acceptType, String capture) { fun openFileChooser(uploadMessage: ValueCallback<Uri?>?, acceptType: String?, capture: String?) {
openFileChooser(uploadMessage); openFileCallback = uploadMessage
} val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
protected void openFileChooser(ValueCallback<Uri> uploadMessage) { intent.type = "*/*"
MainFragment.this.openFileCallback = uploadMessage; startActivityForResult(
Intent intent = new Intent(Intent.ACTION_GET_CONTENT); Intent.createChooser(intent, getString(R.string.file_browser)),
intent.addCategory(Intent.CATEGORY_OPENABLE); REQUEST_FILE_CHOOSER
intent.setType("*/*"); )
startActivityForResult(Intent.createChooser(intent, getString(R.string.file_browser)), REQUEST_FILE_CHOOSER);
} }
// Android 5.0+ // Android 5.0+
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { override fun onShowFileChooser(
if (openFileCallback2 != null) { mWebView: WebView,
openFileCallback2.onReceiveValue(null); filePathCallback: ValueCallback<Array<Uri>>,
openFileCallback2 = null; fileChooserParams: FileChooserParams
} ): Boolean {
openFileCallback2?.onReceiveValue(null)
openFileCallback2 = filePathCallback; openFileCallback2 = filePathCallback
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Intent intent = fileChooserParams.createIntent(); val intent = fileChooserParams.createIntent()
try { try {
startActivityForResult(intent, REQUEST_FILE_CHOOSER); startActivityForResult(intent, REQUEST_FILE_CHOOSER)
} catch (ActivityNotFoundException e) { } catch (e: ActivityNotFoundException) {
openFileCallback2 = null; openFileCallback2 = null
return false; return false
} }
} }
return true; return true
} }
}
}; companion object {
const val EVENT_LOGIN = "eventLogin"
const val EVENT_TOKEN = "eventToken"
const val KEY_TOKEN = "keyToken"
private const val REQUEST_PERMISSIONS_LOCATION = 1
private const val REQUEST_FILE_CHOOSER = 1
}
} }
-143
Просмотреть файл
@@ -1,143 +0,0 @@
/*
* Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.manager;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class StartFragment extends Fragment implements View.OnClickListener {
private static final String TAG = StartFragment.class.getSimpleName();
private static final int MAX_REDIRECTS = 5;
private EditText serverField;
private Button startButton;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_start, container, false);
serverField = (EditText) view.findViewById(R.id.field_server);
startButton = (Button) view.findViewById(R.id.button_start);
startButton.setOnClickListener(this);
return view;
}
@SuppressLint("StaticFieldLeak")
@Override
public void onClick(View view) {
startButton.setEnabled(false);
new AsyncTask<String, Void, Boolean>() {
@Override
protected Boolean doInBackground(String... urls) {
try {
Uri uri = Uri.parse(urls[0]).buildUpon().appendEncodedPath("api/server").build();
String url = uri.toString();
HttpURLConnection urlConnection = null;
for (int i = 0; i < MAX_REDIRECTS; i++) {
URL resourceUrl = new URL(url);
urlConnection = (HttpURLConnection) resourceUrl.openConnection();
urlConnection.setInstanceFollowRedirects(false);
switch (urlConnection.getResponseCode()) {
case HttpURLConnection.HTTP_MOVED_PERM:
case HttpURLConnection.HTTP_MOVED_TEMP:
url = urlConnection.getHeaderField("Location");
continue;
}
break;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
StringBuilder responseBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
responseBuilder.append(line);
}
new JSONObject(responseBuilder.toString());
return true;
} catch (IOException | JSONException e) {
Log.w(TAG, e);
}
return false;
}
@Override
protected void onPostExecute(Boolean result) {
if (getActivity() != null) {
if (result) {
onSuccess();
} else {
onError();
}
}
}
}.execute(serverField.getText().toString());
}
private void onSuccess() {
PreferenceManager.getDefaultSharedPreferences(getActivity())
.edit().putString(MainActivity.PREFERENCE_URL, serverField.getText().toString()).apply();
getActivity().getFragmentManager()
.beginTransaction().replace(android.R.id.content, new MainFragment()).commitAllowingStateLoss();
}
private void onError() {
startButton.setEnabled(true);
AlertDialog alertDialog = new AlertDialog.Builder(getActivity()).create();
alertDialog.setMessage(getString(R.string.error_connection));
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
}
+123
Просмотреть файл
@@ -0,0 +1,123 @@
/*
* Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("DEPRECATION")
package org.traccar.manager
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.Fragment
import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import androidx.preference.PreferenceManager
import org.json.JSONException
import org.json.JSONObject
import org.traccar.manager.StartFragment
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
class StartFragment : Fragment(), View.OnClickListener {
private lateinit var serverField: EditText
private lateinit var startButton: Button
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_start, container, false)
serverField = view.findViewById(R.id.field_server)
startButton = view.findViewById(R.id.button_start)
startButton.setOnClickListener(this)
return view
}
@SuppressLint("StaticFieldLeak")
override fun onClick(view: View) {
startButton.isEnabled = false
object : AsyncTask<String, Unit, Boolean>() {
override fun doInBackground(vararg urls: String): Boolean {
try {
val uri = Uri.parse(urls[0]).buildUpon().appendEncodedPath("api/server").build()
var url = uri.toString()
var urlConnection: HttpURLConnection? = null
for (i in 0 until MAX_REDIRECTS) {
val resourceUrl = URL(url)
urlConnection = resourceUrl.openConnection() as HttpURLConnection
urlConnection.instanceFollowRedirects = false
when (urlConnection.responseCode) {
HttpURLConnection.HTTP_MOVED_PERM, HttpURLConnection.HTTP_MOVED_TEMP -> {
url = urlConnection.getHeaderField("Location")
continue
}
}
break
}
val reader = BufferedReader(InputStreamReader(urlConnection?.inputStream))
var line: String?
val responseBuilder = StringBuilder()
while (reader.readLine().also { line = it } != null) {
responseBuilder.append(line)
}
JSONObject(responseBuilder.toString())
return true
} catch (e: IOException) {
Log.w(TAG, e)
} catch (e: JSONException) {
Log.w(TAG, e)
}
return false
}
override fun onPostExecute(result: Boolean) {
if (activity != null) {
if (result) {
onSuccess()
} else {
onError()
}
}
}
}.execute(serverField.text.toString())
}
private fun onSuccess() {
PreferenceManager.getDefaultSharedPreferences(activity)
.edit().putString(MainActivity.PREFERENCE_URL, serverField.text.toString()).apply()
activity.fragmentManager
.beginTransaction().replace(android.R.id.content, MainFragment())
.commitAllowingStateLoss()
}
private fun onError() {
startButton.isEnabled = true
val alertDialog = AlertDialog.Builder(activity).create()
alertDialog.setMessage(getString(R.string.error_connection))
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, getString(android.R.string.ok)) { dialog, _ -> dialog.dismiss() }
alertDialog.show()
}
companion object {
private val TAG = StartFragment::class.java.simpleName
private const val MAX_REDIRECTS = 5
}
}