diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 0b803370d..935810c29 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -57,7 +57,7 @@ jobs: # Run Instrumentation Tests in Firebase Test Lab - name: Run Instrumentation Tests in Firebase Test Lab - run: gcloud firebase test android run --type instrumentation --app ${{ env.module_app }}/build/outputs/apk/debug/${{ env.module_app }}-debug.apk --test ${{ env.module_app }}/build/outputs/apk/androidTest/debug/${{ env.module_app }}-debug-androidTest.apk --device model=oriole,version=31,locale=en,orientation=portrait + run: gcloud firebase test android run --type instrumentation --app ${{ env.module_app }}/build/outputs/apk/debug/${{ env.module_app }}-debug.apk --test ${{ env.module_app }}/build/outputs/apk/androidTest/debug/${{ env.module_app }}-debug-androidTest.apk --device model=akita,version=34,locale=en,orientation=portrait ########################################## diff --git a/app/build.gradle b/app/build.gradle index 1793a984e..4affd9652 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,14 +2,16 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.firebase.crashlytics' android { - compileSdkVersion 34 + compileSdk 34 useLibrary 'org.apache.http.legacy' defaultConfig { applicationId "org.glpi.inventory.agent" minSdkVersion 21 targetSdkVersion 34 + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true } testOptions { @@ -28,19 +30,10 @@ android { } } - dexOptions { - preDexLibraries true - maxProcessCount 8 - } - namespace 'org.glpi.inventory.agent' lint { abortOnError false } - - defaultConfig { - multiDexEnabled true - } } dependencies { @@ -63,8 +56,8 @@ dependencies { androidTestImplementation 'tools.fastlane:screengrab:2.1.1' - testImplementation 'org.mockito:mockito-core:2.18.3' - androidTestImplementation 'org.mockito:mockito-android:2.18.3' + testImplementation 'org.mockito:mockito-android:5.5.0' // Use the latest version + androidTestImplementation 'org.mockito:mockito-android:5.5.0' implementation 'androidx.test.espresso:espresso-idling-resource:3.6.1' implementation fileTree(dir: 'libs', include: ['*.jar']) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index eaaae5d1a..372a35889 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,10 +1,11 @@ + xmlns:tools="http://schemas.android.com/tools" + android:versionCode="39413" + android:versionName=""> + @@ -30,9 +31,6 @@ android:versionName=""> - - - @@ -56,12 +54,6 @@ android:versionName=""> - - - - - - @@ -72,21 +64,19 @@ android:versionName=""> - - - - - + + - - @@ -96,4 +86,4 @@ android:versionName=""> - + \ No newline at end of file diff --git a/app/src/main/java/org/glpi/inventory/agent/broadcast/BootStartAgent.java b/app/src/main/java/org/glpi/inventory/agent/broadcast/BootStartAgent.java index 1315fa1a5..f173c667a 100644 --- a/app/src/main/java/org/glpi/inventory/agent/broadcast/BootStartAgent.java +++ b/app/src/main/java/org/glpi/inventory/agent/broadcast/BootStartAgent.java @@ -38,53 +38,16 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Build; -import android.preference.PreferenceManager; -import android.widget.Toast; - -import org.flyve.inventory.InventoryLog; -import org.glpi.inventory.agent.service.InventoryService; import org.glpi.inventory.agent.ui.ActivityMain; -import org.glpi.inventory.agent.utils.AgentLog; public class BootStartAgent extends BroadcastReceiver { - TimeAlarm alarm = new TimeAlarm(); - - /** - * It sets an alarm after the user has finished booting - * @param context in which the receiver is running - * @param intent being received - */ @Override public void onReceive(Context context, Intent intent) { - - String action = intent.getAction(); - if(action==null) { - return; + if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { + Intent activityIntent = new Intent(context, ActivityMain.class); + activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(activityIntent); } - - SharedPreferences customSharedPreference = PreferenceManager.getDefaultSharedPreferences(context); - if (customSharedPreference.getBoolean("boot", false)) { - try { - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Intent myIntent = new Intent(context, InventoryService.class); - context.startForegroundService(myIntent); - } else { - Intent myIntent = new Intent(context, ActivityMain.class); - myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(myIntent); - } - }catch(Exception ex) { - Toast.makeText(context, ex.getMessage(), Toast.LENGTH_LONG).show(); - } - } - - if(customSharedPreference.getBoolean("autoStartInventory", false)){ - alarm.setAlarm(context); - } - } } diff --git a/app/src/main/java/org/glpi/inventory/agent/broadcast/InventoryJobScheduler.java b/app/src/main/java/org/glpi/inventory/agent/broadcast/InventoryJobScheduler.java new file mode 100644 index 000000000..4172d2295 --- /dev/null +++ b/app/src/main/java/org/glpi/inventory/agent/broadcast/InventoryJobScheduler.java @@ -0,0 +1,204 @@ +/** + * --------------------------------------------------------------------- + * GLPI Android Inventory Agent + * Copyright (C) 2019 Teclib. + * + * https://glpi-project.org + * + * Based on Flyve MDM Inventory Agent For Android + * Copyright © 2018 Teclib. All rights reserved. + * + * --------------------------------------------------------------------- + * + * LICENSE + * + * This file is part of GLPI Android Inventory Agent. + * + * GLPI Android Inventory Agent is a subproject of GLPI. + * + * GLPI Android Inventory Agent is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * GLPI Android Inventory Agent is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * --------------------------------------------------------------------- + * @copyright Copyright © 2019 Teclib. All rights reserved. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/glpi-project/android-inventory-agent + * @link https://glpi-project.org/glpi-network/ + * --------------------------------------------------------------------- + */ + +package org.glpi.inventory.agent.broadcast; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.job.JobParameters; +import android.app.job.JobService; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.preference.PreferenceManager; +import android.provider.Settings; + +import androidx.core.app.NotificationCompat; + +import org.flyve.inventory.InventoryTask; +import org.glpi.inventory.agent.R; +import org.glpi.inventory.agent.schema.ServerSchema; +import org.glpi.inventory.agent.ui.ActivityMain; +import org.glpi.inventory.agent.utils.AgentLog; +import org.glpi.inventory.agent.utils.Helpers; +import org.glpi.inventory.agent.utils.HttpInventory; +import org.glpi.inventory.agent.utils.LocalPreferences; + +import java.util.ArrayList; +import java.util.Calendar; + +@SuppressLint("SpecifyJobSchedulerIdRange") +public class InventoryJobScheduler extends JobService { + + public static final int INVENTORY_JOB_ID = 4492015; + private static final String NOTIFICATION_CHANNEL_ID = "org.glpi.inventory.agent"; + + @Override + public boolean onStartJob(final JobParameters params) { + HandlerThread handlerThread = new HandlerThread("SomeOtherThread"); + handlerThread.start(); + + Handler handler = new Handler(handlerThread.getLooper()); + handler.post(new Runnable() { + @Override + public void run() { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Run task" + Calendar.getInstance().getTime()); + doInventory(); + jobFinished(params, true); + } + }); + + return true; + } + + private void doInventory() { + Context context = getApplicationContext(); + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Launch inventory from JobScheduler " + Calendar.getInstance().getTime()); + + // check if autoStartInventory is deactivated + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + if (!sharedPreferences.getBoolean("autoStartInventory", false)) { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : The inventory will not be send, is deactivated"); + return; + } + + showPersistentNotification(); + + final InventoryTask inventory = new InventoryTask(context.getApplicationContext(), Helpers.getAgentDescription(context), true); + final HttpInventory httpInventory = new HttpInventory(context.getApplicationContext()); + ArrayList serverArray = new LocalPreferences(context).loadServer(); + if (!serverArray.isEmpty()) { + for (final String serverName : serverArray) { + final ServerSchema model = httpInventory.setServerModel(serverName); + inventory.setTag(model.getTag()); + inventory.setAssetItemtype(model.getItemtype()); + inventory.getXML(new InventoryTask.OnTaskCompleted() { + @Override + public void onTaskSuccess(String data) { + ServerSchema model = httpInventory.setServerModel(serverName); + if(!model.getSerial().trim().isEmpty()) { + data = data.replaceAll("(.*)","" + model.getSerial() + ""); + } + httpInventory.sendInventory(data, model, new HttpInventory.OnTaskCompleted() { + @Override + public void onTaskSuccess(String data) { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Inventory Success"); + Helpers.sendToNotificationBar(context.getApplicationContext(), context.getResources().getString(R.string.inventory_notification_sent)); + //Helpers.sendAnonymousData(context.getApplicationContext(), inventory); + } + + @Override + public void onTaskError(String error) { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Inventory error"); + Helpers.sendToNotificationBar(context.getApplicationContext(), context.getResources().getString(R.string.inventory_notification_fail)); + AgentLog.e(error); + } + }); + } + + @Override + public void onTaskError(Throwable error) { + AgentLog.e(error.getMessage()); + Helpers.sendToNotificationBar(context, context.getResources().getString(R.string.inventory_notification_fail)); + } + }); + } + } else { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : " + context.getResources().getString(R.string.inventory_no_server)); + } + } + + @Override + public boolean onStopJob(final JobParameters params) { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : onStopJob() was called"); + return true; + } + + private void showPersistentNotification() { + NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + // create channel if needed + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + NotificationChannel chan = null; + chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, getString(R.string.app_is_running), NotificationManager.IMPORTANCE_DEFAULT); + chan.setLightColor(Color.BLUE); + chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); + manager.createNotificationChannel(chan); + } + + // create intent to redirect to notification to settings + Intent notificationIntent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationIntent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS); + notificationIntent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); + notificationIntent.putExtra(Settings.EXTRA_CHANNEL_ID, NOTIFICATION_CHANNEL_ID); + notificationIntent.putExtra("app_package", getPackageName()); + notificationIntent.putExtra("app_uid", getApplicationInfo().uid); + notificationIntent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName()); + } else { + notificationIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + notificationIntent.setData(Uri.parse("package:" + getPackageName())); + } + PendingIntent notificationPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); + + + Intent appIntent = new Intent(this, ActivityMain.class); + appIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); + PendingIntent appIntentRedirect = PendingIntent.getActivity(this, 0, appIntent, PendingIntent.FLAG_IMMUTABLE); + + // create notification + NotificationCompat.Builder notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID); + notification.setOngoing(false); + notification.setSmallIcon(R.drawable.ic_stat); + notification.setContentTitle(getString(R.string.app_is_running)); + notification.setContentText(getString(R.string.agent_description)); + notification.setCategory(Notification.CATEGORY_EVENT); + notification.setPriority(NotificationCompat.PRIORITY_DEFAULT); + notification.setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.app_is_running_extend))); + notification.setContentIntent(appIntentRedirect); + notification.addAction(R.drawable.ic_stat, getString(R.string.disable_notification), notificationPendingIntent); + + // notify + manager.notify(1, notification.build()); + } +} diff --git a/app/src/main/java/org/glpi/inventory/agent/broadcast/TimeAlarm.java b/app/src/main/java/org/glpi/inventory/agent/broadcast/TimeAlarm.java deleted file mode 100644 index 360d92aba..000000000 --- a/app/src/main/java/org/glpi/inventory/agent/broadcast/TimeAlarm.java +++ /dev/null @@ -1,175 +0,0 @@ -/** - * --------------------------------------------------------------------- - * GLPI Android Inventory Agent - * Copyright (C) 2019 Teclib. - * - * https://glpi-project.org - * - * Based on Flyve MDM Inventory Agent For Android - * Copyright © 2018 Teclib. All rights reserved. - * - * --------------------------------------------------------------------- - * - * LICENSE - * - * This file is part of GLPI Android Inventory Agent. - * - * GLPI Android Inventory Agent is a subproject of GLPI. - * - * GLPI Android Inventory Agent is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * GLPI Android Inventory Agent is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * --------------------------------------------------------------------- - * @copyright Copyright © 2019 Teclib. All rights reserved. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/glpi-project/android-inventory-agent - * @link https://glpi-project.org/glpi-network/ - * --------------------------------------------------------------------- - */ - -package org.glpi.inventory.agent.broadcast; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Build; -import android.os.PowerManager; -import android.preference.PreferenceManager; - -import androidx.annotation.RequiresApi; - -import org.flyve.inventory.InventoryTask; -import org.glpi.inventory.agent.R; -import org.glpi.inventory.agent.schema.ServerSchema; -import org.glpi.inventory.agent.utils.AgentLog; -import org.glpi.inventory.agent.utils.Helpers; -import org.glpi.inventory.agent.utils.HttpInventory; -import org.glpi.inventory.agent.utils.LocalPreferences; - -import java.util.ArrayList; - -public class TimeAlarm extends BroadcastReceiver { - - /** - * If the success XML is created, it sends the inventory - * @param context in which the receiver is running - * @param intent being received - */ - @Override - public void onReceive(final Context context, Intent intent) { - - // check if is deactivated - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - Boolean val = sharedPreferences.getBoolean("autoStartInventory", false); - if (!val) { - AgentLog.d("The inventory will not be send, is deactivated"); - return; - } - - AgentLog.d("Launch inventory from alarm"); - - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); - wl.acquire(); - - final InventoryTask inventory = new InventoryTask(context.getApplicationContext(), Helpers.getAgentDescription(context), true); - final HttpInventory httpInventory = new HttpInventory(context.getApplicationContext()); - ArrayList serverArray = new LocalPreferences(context).loadServer(); - if (!serverArray.isEmpty()) { - for (final String serverName : serverArray) { - final ServerSchema model = httpInventory.setServerModel(serverName); - inventory.setTag(model.getTag()); - inventory.setAssetItemtype(model.getItemtype()); - inventory.getXML(new InventoryTask.OnTaskCompleted() { - @Override - public void onTaskSuccess(String data) { - ServerSchema model = httpInventory.setServerModel(serverName); - if(!model.getSerial().trim().isEmpty()) { - data = data.replaceAll("(.*)","" + model.getSerial() + ""); - } - httpInventory.sendInventory(data, model, new HttpInventory.OnTaskCompleted() { - @Override - public void onTaskSuccess(String data) { - Helpers.sendToNotificationBar(context.getApplicationContext(), context.getResources().getString(R.string.inventory_notification_sent)); - //Helpers.sendAnonymousData(context.getApplicationContext(), inventory); - } - - @Override - public void onTaskError(String error) { - Helpers.sendToNotificationBar(context.getApplicationContext(), context.getResources().getString(R.string.inventory_notification_fail)); - AgentLog.e(error); - } - }); - } - - @Override - public void onTaskError(Throwable error) { - AgentLog.e(error.getMessage()); - Helpers.sendToNotificationBar(context, context.getResources().getString(R.string.inventory_notification_fail)); - } - }); - } - } else { - AgentLog.e(context.getResources().getString(R.string.inventory_no_server)); - } - - wl.release(); - } - - /** - * Schedules the alarm - * @param context - */ - @RequiresApi(api = Build.VERSION_CODES.M) - public void setAlarm(Context context) { - - AgentLog.d("Set Alarm"); - - AlarmManager am =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(context, TimeAlarm.class); - i.setAction("org.glpi.inventory.agent.ALARM"); - PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_IMMUTABLE); - - SharedPreferences customSharedPreference = PreferenceManager.getDefaultSharedPreferences(context); - String timeInventory = customSharedPreference.getString("timeInventory", "Week"); - - int time = 60 * 1000; - - if (timeInventory.equals("Day")) { - time = 24 * 60 * 60 * 1000; - AgentLog.d("Alarm Daily"); - } else if(timeInventory.equals("Week")) { - time = 7 * 24 * 60 * 60 * 1000; - AgentLog.d("Alarm Weekly"); - } else if(timeInventory.equals("Month")) { - time = 30 * 24 * 60 * 60 * 1000; - AgentLog.d("Alarm Monthly"); - } - - try { - am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), time, pi); - } catch (NullPointerException ex) { - AgentLog.e(ex.getMessage()); - } - } - - /** - * Removes the alarm with a matching argument - * @param context - */ - public void cancelAlarm(Context context) { - Intent intent = new Intent(context, TimeAlarm.class); - PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0); - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - alarmManager.cancel(sender); - } -} diff --git a/app/src/main/java/org/glpi/inventory/agent/core/home/Home.java b/app/src/main/java/org/glpi/inventory/agent/core/home/Home.java index bf30bead0..81cfbc314 100644 --- a/app/src/main/java/org/glpi/inventory/agent/core/home/Home.java +++ b/app/src/main/java/org/glpi/inventory/agent/core/home/Home.java @@ -54,14 +54,12 @@ interface Presenter { void showError(String message); // Models - void doBindService(Activity activity); void setupList(Activity activity, ListView lst); void clickItem(final Activity activity, HomeSchema homeSchema); List getListItems(); } interface Model { - void doBindService(Activity activity); void setupList(Activity activity, ListView lst); void clickItem(final Activity activity, HomeSchema homeSchema); List getListItems(); diff --git a/app/src/main/java/org/glpi/inventory/agent/core/home/HomeModel.java b/app/src/main/java/org/glpi/inventory/agent/core/home/HomeModel.java index b4b89e3e8..d6635ce6c 100644 --- a/app/src/main/java/org/glpi/inventory/agent/core/home/HomeModel.java +++ b/app/src/main/java/org/glpi/inventory/agent/core/home/HomeModel.java @@ -36,22 +36,15 @@ package org.glpi.inventory.agent.core.home; import android.app.Activity; -import android.app.ActivityManager; -import android.content.ComponentName; -import android.content.Context; import android.content.Intent; -import android.os.Build; -import android.util.Log; import android.widget.ListView; import org.glpi.inventory.agent.R; import org.glpi.inventory.agent.adapter.HomeAdapter; import org.glpi.inventory.agent.preference.GlobalParametersPreference; import org.glpi.inventory.agent.preference.InventoryParametersPreference; -import org.glpi.inventory.agent.service.InventoryService; import org.glpi.inventory.agent.ui.ActivityInventoryReport; import org.glpi.inventory.agent.ui.DialogListServers; -import org.glpi.inventory.agent.utils.AgentLog; import java.util.ArrayList; import java.util.List; @@ -65,53 +58,6 @@ public HomeModel(Home.Presenter presenter) { this.presenter = presenter; } - public void doBindService(Activity activity) { - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - InventoryService inventoryService = new InventoryService(); - Intent mServiceIntent = new Intent(activity, inventoryService.getClass()); - ComponentName result; - - if (!isMyServiceRunning(activity, inventoryService.getClass())) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - result = activity.startForegroundService(mServiceIntent); - } else { - result = activity.startService(mServiceIntent); - } - - if (result != null) { - AgentLog.log(this, " Agent started ", Log.INFO); - } else { - AgentLog.log(this, " Agent fail", Log.ERROR); - } - } else { - AgentLog.log(this, " Agent already started ", Log.ERROR); - } - } - - /** - * Check if the service is running - * @param serviceClass Class - * @return boolean - */ - private boolean isMyServiceRunning(Activity activity, Class serviceClass) { - try { - ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); - for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { - if (serviceClass.getName().equals(service.service.getClassName())) { - return true; - } - } - } catch (Exception ex) { - AgentLog.e(ex.getMessage()); - } - - return false; - } - - @Override public void setupList(Activity activity, ListView lst) { arrHome = new ArrayList<>(); diff --git a/app/src/main/java/org/glpi/inventory/agent/core/home/HomePresenter.java b/app/src/main/java/org/glpi/inventory/agent/core/home/HomePresenter.java index afc2b2d2d..f443a5f76 100644 --- a/app/src/main/java/org/glpi/inventory/agent/core/home/HomePresenter.java +++ b/app/src/main/java/org/glpi/inventory/agent/core/home/HomePresenter.java @@ -57,11 +57,6 @@ public void showError(String message) { } } - @Override - public void doBindService(Activity activity) { - model.doBindService(activity); - } - @Override public void setupList(Activity activity, ListView lst) { model.setupList(activity, lst); diff --git a/app/src/main/java/org/glpi/inventory/agent/core/main/MainModel.java b/app/src/main/java/org/glpi/inventory/agent/core/main/MainModel.java index d3001291e..b9e99aad9 100644 --- a/app/src/main/java/org/glpi/inventory/agent/core/main/MainModel.java +++ b/app/src/main/java/org/glpi/inventory/agent/core/main/MainModel.java @@ -46,6 +46,7 @@ import org.glpi.inventory.agent.R; import org.glpi.inventory.agent.adapter.DrawerAdapter; +import org.glpi.inventory.agent.ui.ActivityMain; import org.glpi.inventory.agent.ui.FragmentAbout; import org.glpi.inventory.agent.ui.FragmentHelp; import org.glpi.inventory.agent.ui.FragmentHome; @@ -70,30 +71,9 @@ public MainModel(Main.Presenter presenter) { @Override public void setupInventoryAlarm(Context context) { - LocalStorage cache = new LocalStorage(context); - if (cache.getDataBoolean("changeSchedule")) { - Calendar calendar = Calendar.getInstance(); - - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - String timeInventory = sharedPreferences.getString("timeInventory", "week"); - - // week by default - if (timeInventory.equalsIgnoreCase("week")) { - calendar.add(Calendar.DATE, 7); - } - - if (timeInventory.equalsIgnoreCase("day")) { - calendar.add(Calendar.DATE, 1); - } - - if (timeInventory.equalsIgnoreCase("month")) { - calendar.add(Calendar.DATE, 30); - } - - long dateTime = calendar.getTime().getTime(); - - cache.setDataLong("data", dateTime); - cache.setDataBoolean("changeSchedule", false); + if (context instanceof ActivityMain) { + ActivityMain activity = (ActivityMain) context; + activity.scheduleJob(); } } diff --git a/app/src/main/java/org/glpi/inventory/agent/preference/InventoryParametersPreference.java b/app/src/main/java/org/glpi/inventory/agent/preference/InventoryParametersPreference.java index 72f771084..ca04e7f70 100644 --- a/app/src/main/java/org/glpi/inventory/agent/preference/InventoryParametersPreference.java +++ b/app/src/main/java/org/glpi/inventory/agent/preference/InventoryParametersPreference.java @@ -73,15 +73,16 @@ public void onClick(View v) { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - if ("timeInventory".equals(s)) { Intent intent = new Intent("timeAlarmChanged"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); - AgentLog.d("Preference "+ s +" changed -> " + sharedPreferences.getString(s, "Week")); + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Preference "+ s +" changed -> " + sharedPreferences.getString(s, "Week")); } if("autoStartInventory".equals(s)){ - AgentLog.d("Preference "+ s +" changed -> " + sharedPreferences.getBoolean(s, false)); + Intent intent = new Intent("timeAlarmChanged"); + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Preference "+ s +" changed -> " + sharedPreferences.getBoolean(s, false)); } } } diff --git a/app/src/main/java/org/glpi/inventory/agent/service/InventoryService.java b/app/src/main/java/org/glpi/inventory/agent/service/InventoryService.java deleted file mode 100644 index c7e1e223a..000000000 --- a/app/src/main/java/org/glpi/inventory/agent/service/InventoryService.java +++ /dev/null @@ -1,313 +0,0 @@ -/** - * --------------------------------------------------------------------- - * GLPI Android Inventory Agent - * Copyright (C) 2019 Teclib. - * - * https://glpi-project.org - * - * Based on Flyve MDM Inventory Agent For Android - * Copyright © 2018 Teclib. All rights reserved. - * - * --------------------------------------------------------------------- - * - * LICENSE - * - * This file is part of GLPI Android Inventory Agent. - * - * GLPI Android Inventory Agent is a subproject of GLPI. - * - * GLPI Android Inventory Agent is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * GLPI Android Inventory Agent is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * --------------------------------------------------------------------- - * @copyright Copyright © 2019 Teclib. All rights reserved. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/glpi-project/android-inventory-agent - * @link https://glpi-project.org/glpi-network/ - * --------------------------------------------------------------------- - */ - -package org.glpi.inventory.agent.service; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Color; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.os.PowerManager; -import android.preference.PreferenceManager; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.core.app.NotificationCompat; -import android.util.Log; -import android.util.Xml; - -import org.flyve.inventory.InventoryTask; -import org.glpi.inventory.agent.R; -import org.glpi.inventory.agent.schema.ServerSchema; -import org.glpi.inventory.agent.ui.ActivityMain; -import org.glpi.inventory.agent.utils.AgentLog; -import org.glpi.inventory.agent.utils.Helpers; -import org.glpi.inventory.agent.utils.HttpInventory; -import org.glpi.inventory.agent.utils.LocalPreferences; -import org.glpi.inventory.agent.utils.LocalStorage; -import org.glpi.inventory.agent.utils.Utils; -import org.xmlpull.v1.XmlSerializer; - -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; - -public class InventoryService extends Service { - - public static final String TIMER_RECEIVER = "org.glpi.inventory.service.timer"; - - private Handler mHandler; - Calendar calendar; - long longDate; - Date dateCurrent, dateDiff; - LocalStorage cache; - - private Timer mTimer = null; - public static final long NOTIFY_INTERVAL = 1000; - Intent intent; - - @Nullable - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public void onCreate() { - super.onCreate(); - - mHandler = new Handler(); - - cache = new LocalStorage(getApplicationContext()); - calendar = Calendar.getInstance(); - - mTimer = new Timer(); - mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 5, NOTIFY_INTERVAL); - intent = new Intent(TIMER_RECEIVER); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startMyOwnForeground(); - } - - } - - @RequiresApi(api = Build.VERSION_CODES.O) - private void startMyOwnForeground(){ - String NOTIFICATION_CHANNEL_ID = "org.glpi.inventory.agent"; - String channelName = getApplicationContext().getResources().getString(R.string.app_is_running); - NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE); - chan.setLightColor(Color.BLUE); - chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); - NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - assert manager != null; - manager.createNotificationChannel(chan); - - //create intent to redirect user to app on click - Intent appIntent = new Intent(getApplicationContext(), ActivityMain.class); - appIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - PendingIntent appIntentRedirect = PendingIntent.getActivity(getApplicationContext(), 0, appIntent, PendingIntent.FLAG_MUTABLE); - - - //create inent to invite user to disable notification - Intent notificationIntent = new Intent(); - notificationIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); - notificationIntent.putExtra("app_package", getPackageName()); - notificationIntent.putExtra("app_uid", getApplicationInfo().uid); - notificationIntent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName()); - PendingIntent notificationIntentRedirect = PendingIntent.getActivity(getApplicationContext(), 0, - notificationIntent, PendingIntent.FLAG_MUTABLE); - - //create notification - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID); - Notification notification = notificationBuilder.setOngoing(true) - .setSmallIcon(R.drawable.ic_stat) - .setContentTitle(getApplicationContext().getResources().getString(R.string.app_is_running)) - .setPriority(NotificationManager.IMPORTANCE_MIN) - .setCategory(Notification.CATEGORY_SERVICE) - .setStyle(new NotificationCompat.BigTextStyle() - .bigText(getApplicationContext().getResources().getString(R.string.app_is_running_extend))) - .setContentIntent(appIntentRedirect) - .addAction(R.drawable.ic_about, getApplicationContext().getResources().getString(R.string.disable_notification), notificationIntentRedirect) - .build(); - startForeground(2, notification); - } - - class TimeDisplayTimerTask extends TimerTask { - @Override - public void run() { - mHandler.post(new Runnable() { - - @Override - public void run() { - calendar = Calendar.getInstance(); - longDate = calendar.getTime().getTime(); - Log.i("strDate", String.valueOf(longDate)); - twoDatesBetweenTime(); - } - - }); - } - } - - private void twoDatesBetweenTime() { - - try { - dateCurrent = new Date(longDate); - } catch (Exception ex) { - AgentLog.e(ex.getMessage()); - } - - try { - dateDiff = new Date(cache.getDataLong("data")); - } catch (Exception ex) { - AgentLog.e(ex.getMessage()); - } - - try { - long diff = dateDiff.getTime() - dateCurrent.getTime(); - - long days = TimeUnit.MILLISECONDS.toDays(diff); - diff -= TimeUnit.DAYS.toMillis(days); - - long hours = TimeUnit.MILLISECONDS.toHours(diff); - diff -= TimeUnit.HOURS.toMillis(hours); - - long minutes = TimeUnit.MILLISECONDS.toMinutes(diff); - diff -= TimeUnit.MINUTES.toMillis(minutes); - - long seconds = TimeUnit.MILLISECONDS.toSeconds(diff); - - if (seconds + hours + minutes + days > 0) { - String strTesting; - if (days != 0) - strTesting = days + " days " + hours + ":" + minutes + ":" + seconds; - else - strTesting = hours + ":" + minutes + ":" + seconds; - updateTime(strTesting); - } else { - sendInventory(); - setupInventorySchedule(); - } - } catch (Exception e) { - mTimer.cancel(); - mTimer.purge(); - } - - } - - private void setupInventorySchedule() { - calendar = Calendar.getInstance(); - - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - String timeInventory = sharedPreferences.getString("timeInventory", "week"); - - // week by default - if (timeInventory.equalsIgnoreCase("week")) { - calendar.add(Calendar.DATE, 7); - } - - if(timeInventory.equalsIgnoreCase("day")) { - calendar.add(Calendar.DATE, 1); - } - - if(timeInventory.equalsIgnoreCase("month")) { - calendar.add(Calendar.DATE, 30); - } - - long dateTime = calendar.getTime().getTime(); - - cache = new LocalStorage(getApplicationContext()); - cache.setDataLong("data", dateTime); - } - - private void sendInventory() { - final Context context = getApplicationContext(); - - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - Boolean autoStartInventory = sharedPreferences.getBoolean("autoStartInventory", false); - if(!autoStartInventory) { return; } - - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "android:inventory:agent"); - wl.acquire(); - - final InventoryTask inventory = new InventoryTask(context.getApplicationContext(), Helpers.getAgentDescription(context), true); - final HttpInventory httpInventory = new HttpInventory(context.getApplicationContext()); - ArrayList serverArray = new LocalPreferences(context).loadServer(); - if (!serverArray.isEmpty()) { - for (String serverName : serverArray) { - final ServerSchema model = httpInventory.setServerModel(serverName); - inventory.setTag(model.getTag()); - inventory.setAssetItemtype(model.getItemtype()); - inventory.getXML(new InventoryTask.OnTaskCompleted() { - @Override - public void onTaskSuccess(String data) { - if(!model.getSerial().trim().isEmpty()) { - data = data.replaceAll("(.*)","" + model.getSerial() + ""); - } - httpInventory.sendInventory(data, model, new HttpInventory.OnTaskCompleted() { - @Override - public void onTaskSuccess(String data) { - Helpers.sendToNotificationBar(context.getApplicationContext(), context.getResources().getString(R.string.inventory_notification_sent)); - //Helpers.sendAnonymousData(context.getApplicationContext(), inventory); - } - - @Override - public void onTaskError(String error) { - Helpers.sendToNotificationBar(context.getApplicationContext(), error); - AgentLog.e(error); - } - }); - } - - @Override - public void onTaskError(Throwable error) { - AgentLog.e(error.getMessage()); - Helpers.sendToNotificationBar(context, context.getResources().getString(R.string.inventory_notification_fail)); - } - }); - } - } else { - Helpers.sendToNotificationBar(context.getApplicationContext(), context.getResources().getString(R.string.no_servers_added)); - AgentLog.e(context.getResources().getString(R.string.no_servers_added)); - } - - wl.release(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log.e("Service finish", "Finish"); - getApplicationContext().startService(new Intent(getApplicationContext(), InventoryService.class)); - } - - private void updateTime(String strTime) { - intent.putExtra("time", strTime); - sendBroadcast(intent); - } -} diff --git a/app/src/main/java/org/glpi/inventory/agent/ui/ActivityMain.java b/app/src/main/java/org/glpi/inventory/agent/ui/ActivityMain.java index a78c87e3d..4f921df09 100644 --- a/app/src/main/java/org/glpi/inventory/agent/ui/ActivityMain.java +++ b/app/src/main/java/org/glpi/inventory/agent/ui/ActivityMain.java @@ -36,7 +36,10 @@ package org.glpi.inventory.agent.ui; import android.Manifest; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -45,7 +48,6 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.Parcelable; import android.preference.PreferenceManager; @@ -53,14 +55,13 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.enterprise.feedback.KeyedAppState; import androidx.enterprise.feedback.KeyedAppStatesReporter; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.provider.Settings; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -70,28 +71,25 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; -import org.flyve.inventory.InventoryTask; import org.glpi.inventory.agent.R; -import org.glpi.inventory.agent.core.detailserver.DetailServer; -import org.glpi.inventory.agent.core.detailserver.DetailServerPresenter; +import org.glpi.inventory.agent.broadcast.InventoryJobScheduler; import org.glpi.inventory.agent.core.main.Main; import org.glpi.inventory.agent.core.main.MainPresenter; import org.glpi.inventory.agent.preference.GlobalParametersPreference; import org.glpi.inventory.agent.preference.InventoryParametersPreference; -import org.glpi.inventory.agent.schema.ServerSchema; -import org.glpi.inventory.agent.service.InventoryService; import org.glpi.inventory.agent.utils.AgentLog; import org.glpi.inventory.agent.utils.Helpers; -import org.glpi.inventory.agent.utils.HttpInventory; import org.glpi.inventory.agent.utils.LocalPreferences; import org.glpi.inventory.agent.utils.LocalStorage; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; public class ActivityMain extends AppCompatActivity implements Main.View, SharedPreferences.OnSharedPreferenceChangeListener { @@ -107,18 +105,7 @@ public class ActivityMain extends AppCompatActivity private Boolean isOpen; private Animation fab_open, fab_close, fab_clock, fab_anticlock; private TextView textview_settings, textview_scheduler; - - private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String strTime = intent.getStringExtra("time"); - if (sharedPreferences.getBoolean("autoStartInventory", false)) { - toolbar.setSubtitle(strTime); - } else { - toolbar.setSubtitle(""); - } - } - }; + InventoryJobScheduler alarm = new InventoryJobScheduler(); private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { @Override @@ -129,23 +116,45 @@ public void onReceive(Context context, Intent intent) { }; private BroadcastReceiver appRestrictionChange = null; - private KeyedAppStatesReporter appRestrictionChangeReporter = null; @Override protected void onStart() { super.onStart(); - IntentFilter restrictionsFilter = - new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); - + IntentFilter restrictionsFilter = new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); BroadcastReceiver appRestrictionChange = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { resolveRestrictions(); } }; - registerReceiver(appRestrictionChange, restrictionsFilter); + if (Build.VERSION.SDK_INT >= 34) { + registerReceiver(appRestrictionChange, restrictionsFilter, RECEIVER_EXPORTED); + } else { + registerReceiver(appRestrictionChange, restrictionsFilter); + } + + if (sharedPreferences.getBoolean("autoStartInventory", false)) { + String label = getString(R.string.schedule_inventory_each); + String frequency = "weekly"; + switch(sharedPreferences.getString("timeInventory", "Week")){ + case "Day": + frequency = "daily"; + break; + case "Month": + frequency = "monthly"; + break; + default: + frequency = "weekly"; + break; + } + + toolbar.setSubtitle(label + ' ' + frequency); + } else { + toolbar.setSubtitle("Scheduled inventory not configured"); + } } + @Override protected void onStop() { super.onStop(); @@ -155,136 +164,52 @@ protected void onStop() { } } - public static void enterpriseFeedback(Context context, - String key, - String message, - String data, - int severity) { - KeyedAppStatesReporter keyedAppStatesReporter = KeyedAppStatesReporter.create(context); - KeyedAppState keyedAppStateMessage = KeyedAppState.builder() - .setSeverity(severity) - .setKey(key) - .setMessage(message) - .setData(data) - .build(); - List list = new ArrayList<>(); - list.add(keyedAppStateMessage); - keyedAppStatesReporter.setStates(list); + @Override + protected void onResume() { + super.onResume(); + resolveRestrictions(); } - private void resolveRestrictions() { - AgentLog.e("EMM - START resolve restrictions"); - RestrictionsManager myRestrictionsMgr = null; - myRestrictionsMgr = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE); - Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions(); + @Override + protected void onPause() { + super.onPause(); + //unregisterReceiver(broadcastReceiver); + } - SharedPreferences customSharedPreference = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - SharedPreferences.Editor editor = customSharedPreference.edit(); + private void checkPermissions() { + List permissionsList = new ArrayList<>(Arrays.asList( + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.CAMERA + )); - if (appRestrictions.containsKey("automatic_inventory")) { - editor.putBoolean("autoStartInventory", appRestrictions.getBoolean("automatic_inventory")); - enterpriseFeedback(getApplicationContext(), "automatic_inventory", "automatic_inventory option set successfully", appRestrictions.getBoolean("automatic_inventory") ? "true" : "false", KeyedAppState.SEVERITY_INFO); - AgentLog.e("EMM - set automatic inventory to " + appRestrictions.getBoolean("automatic_inventory")); - editor.apply(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + permissionsList.add(Manifest.permission.POST_NOTIFICATIONS); } - if (appRestrictions.containsKey("frequency")) { - editor.putString("timeInventory", appRestrictions.getString("frequency")); - enterpriseFeedback(getApplicationContext(), "frequency", "frequency option set successfully", appRestrictions.getString("frequency"), KeyedAppState.SEVERITY_INFO); - AgentLog.e("EMM - set frequency to " + appRestrictions.getString("frequency")); - editor.apply(); - } + String[] permissions = permissionsList.toArray(new String[0]); - if (appRestrictions.containsKey("auto_start_on_boot")) { - editor.putBoolean("boot", appRestrictions.getBoolean("auto_start_on_boot")); - enterpriseFeedback(getApplicationContext(), "auto_start_on_boot", "auto_start_on_boot option set successfully", appRestrictions.getBoolean("auto_start_on_boot") ? "true" : "false", KeyedAppState.SEVERITY_INFO); - AgentLog.e("EMM - set auto start on boot to " + appRestrictions.getBoolean("auto_start_on_boot")); - editor.apply(); - } - - Parcelable[] parcelables = appRestrictions.getParcelableArray("server_configuration_list"); - if (parcelables != null && parcelables.length > 0) { - final Context context = getApplicationContext(); - for (int i = 0; i < parcelables.length; i++) { - Bundle serverConfig = (Bundle) parcelables[i]; - JSONObject jsonServerConfig = new JSONObject(); - LocalPreferences preferences = new LocalPreferences(context); - - if (serverConfig.getString("server_url").isEmpty()) { - enterpriseFeedback(getApplicationContext(), "server_url", "Error server URL is mandatory -> ", serverConfig.getString("server_url"), KeyedAppState.SEVERITY_ERROR); - AgentLog.e("EMM - server url is mandatory"); - continue; - } - - try { - jsonServerConfig.put("address", serverConfig.getString("server_url")); - jsonServerConfig.put("tag", serverConfig.getString("server_tag")); - jsonServerConfig.put("login", serverConfig.getString("server_login")); - jsonServerConfig.put("pass", serverConfig.getString("server_password")); - jsonServerConfig.put("itemtype", serverConfig.getString("server_itemtype")); - jsonServerConfig.put("serial", serverConfig.getString("server_custom_asset_serial")); - - AgentLog.e("EMM - Receive the following configuration '" + jsonServerConfig.toString()); - - JSONObject local_server = preferences.loadJSONObject(serverConfig.getString("server_url")); - AgentLog.e("EMM - Try to load '" + serverConfig.getString("server_url") + "' server if exist"); - AgentLog.e("EMM - Found '" + local_server.toString() + "'"); - AgentLog.e("EMM - Exist ? -> '" + !local_server.toString().equals("{}") + "'"); - - if (local_server.toString().equals("{}")) { - ArrayList serverArray = preferences.loadServer(); - serverArray.add(serverConfig.getString("server_url")); - preferences.saveServer(serverArray); - preferences.saveJSONObject(serverConfig.getString("server_url"), jsonServerConfig); - enterpriseFeedback(getApplicationContext(), "server_url", "server_url added successfully", serverConfig.getString("server_url"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_tag", "server_tag added successfully", serverConfig.getString("server_tag"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_login", "server_login added successfully", serverConfig.getString("server_login"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_password", "server_password added successfully", "***", KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_itemtype", "server_itemtype added successfully", serverConfig.getString("server_itemtype"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_custom_asset_serial", "server_custom_asset_serial added successfully", serverConfig.getString("server_custom_asset_serial"), KeyedAppState.SEVERITY_INFO); - AgentLog.e("EMM - Server added successfully"); - } else { - preferences.deletePreferences(serverConfig.getString("server_url")); - preferences.saveJSONObject(serverConfig.getString("server_url"), jsonServerConfig); - enterpriseFeedback(getApplicationContext(), "server_url", "server_url updated successfully", serverConfig.getString("server_url"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_tag", "server_tag updated successfully", serverConfig.getString("server_tag"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_login", "server_login updated successfully", serverConfig.getString("server_login"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_password", "server_password updated successfully", "***", KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_itemtype", "server_itemtype updated successfully", serverConfig.getString("server_itemtype"), KeyedAppState.SEVERITY_INFO); - enterpriseFeedback(getApplicationContext(), "server_custom_asset_serial", "server_custom_asset_serial updated successfully", serverConfig.getString("server_custom_asset_serial"), KeyedAppState.SEVERITY_INFO); - AgentLog.e("EMM - Server updated successfully"); - } - - } catch (JSONException e) { - enterpriseFeedback(getApplicationContext(), "server_url", "error while adding/updating server -> " + e.getMessage(), serverConfig.getString("server_url"), KeyedAppState.SEVERITY_ERROR); - AgentLog.e("EMM - error while adding/updating server"); - AgentLog.e("EMM - " + e.getMessage()); - } + List permissionsToRequest = new ArrayList<>(); + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + permissionsToRequest.add(permission); } - } else { - AgentLog.e("EMM - 'server_configuration_list' key is empty"); } - AgentLog.e("EMM - END resolve restrictions"); - } - @Override - protected void onResume() { - super.onResume(); - registerReceiver(broadcastReceiver,new IntentFilter(InventoryService.TIMER_RECEIVER)); - resolveRestrictions(); - } - - @Override - protected void onPause() { - super.onPause(); - unregisterReceiver(broadcastReceiver); + if (!permissionsToRequest.isEmpty()) { + ActivityCompat.requestPermissions(this, permissionsToRequest.toArray(new String[0]), 0); + } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - //Fabric.with(this, new Crashlytics()); + + checkPermissions(); + setContentView(R.layout.activity_main); + if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1); + } ActivityCompat.requestPermissions(ActivityMain.this, new String[]{ @@ -297,6 +222,8 @@ protected void onCreate(Bundle savedInstanceState) { loadCategories(); } + scheduleJob(); + // Menu list ListView lst = findViewById(R.id.lst); @@ -386,11 +313,6 @@ public void onClick(View view) { ActivityMain.this.startActivity(miIntent); } }); - - //app restriction change - KeyedAppStatesReporter appRestrictionChangeReporter = KeyedAppStatesReporter.create(getApplicationContext()); - - } private void disableFab(){ @@ -470,20 +392,195 @@ public void onBackPressed() { } @Override - public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - switch (requestCode) { - case 1: { + boolean allGranted = true; + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + allGranted = false; + break; + } + } - // If request is cancelled, the result arrays are empty. - if (grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED - && grantResults[1] == PackageManager.PERMISSION_GRANTED) { - } else { - String message = getResources().getString(R.string.permission_error_result); - Helpers.snackClose(ActivityMain.this, message, getString(R.string.permission_snack_ok), true); + if (!allGranted) { + String message = getResources().getString(R.string.permission_error_result); + Helpers.snackClose(ActivityMain.this, message, getString(R.string.permission_snack_ok), true); + } + } + + public static void enterpriseFeedback(Context context, + String key, + String message, + String data, + int severity) { + KeyedAppStatesReporter keyedAppStatesReporter = KeyedAppStatesReporter.create(context); + KeyedAppState keyedAppStateMessage = KeyedAppState.builder() + .setSeverity(severity) + .setKey(key) + .setMessage(message) + .setData(data) + .build(); + List list = new ArrayList<>(); + list.add(keyedAppStateMessage); + keyedAppStatesReporter.setStates(list); + } + + private void resolveRestrictions() { + AgentLog.e("EMM - START resolve restrictions"); + RestrictionsManager myRestrictionsMgr = null; + myRestrictionsMgr = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE); + Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions(); + + SharedPreferences customSharedPreference = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor editor = customSharedPreference.edit(); + + if (appRestrictions.containsKey("automatic_inventory")) { + editor.putBoolean("autoStartInventory", appRestrictions.getBoolean("automatic_inventory")); + enterpriseFeedback(getApplicationContext(), "automatic_inventory", "automatic_inventory option set successfully", appRestrictions.getBoolean("automatic_inventory") ? "true" : "false", KeyedAppState.SEVERITY_INFO); + AgentLog.e("EMM - set automatic inventory to " + appRestrictions.getBoolean("automatic_inventory")); + editor.apply(); + } + + if (appRestrictions.containsKey("frequency")) { + editor.putString("timeInventory", appRestrictions.getString("frequency")); + enterpriseFeedback(getApplicationContext(), "frequency", "frequency option set successfully", appRestrictions.getString("frequency"), KeyedAppState.SEVERITY_INFO); + AgentLog.e("EMM - set frequency to " + appRestrictions.getString("frequency")); + editor.apply(); + } + + if (appRestrictions.containsKey("auto_start_on_boot")) { + editor.putBoolean("boot", appRestrictions.getBoolean("auto_start_on_boot")); + enterpriseFeedback(getApplicationContext(), "auto_start_on_boot", "auto_start_on_boot option set successfully", appRestrictions.getBoolean("auto_start_on_boot") ? "true" : "false", KeyedAppState.SEVERITY_INFO); + AgentLog.e("EMM - set auto start on boot to " + appRestrictions.getBoolean("auto_start_on_boot")); + editor.apply(); + } + + Parcelable[] parcelables = appRestrictions.getParcelableArray("server_configuration_list"); + if (parcelables != null && parcelables.length > 0) { + final Context context = getApplicationContext(); + for (int i = 0; i < parcelables.length; i++) { + Bundle serverConfig = (Bundle) parcelables[i]; + JSONObject jsonServerConfig = new JSONObject(); + LocalPreferences preferences = new LocalPreferences(context); + + if (serverConfig.getString("server_url").isEmpty()) { + enterpriseFeedback(getApplicationContext(), "server_url", "Error server URL is mandatory -> ", serverConfig.getString("server_url"), KeyedAppState.SEVERITY_ERROR); + AgentLog.e("EMM - server url is mandatory"); + continue; + } + + try { + jsonServerConfig.put("address", serverConfig.getString("server_url")); + jsonServerConfig.put("tag", serverConfig.getString("server_tag")); + jsonServerConfig.put("login", serverConfig.getString("server_login")); + jsonServerConfig.put("pass", serverConfig.getString("server_password")); + jsonServerConfig.put("itemtype", serverConfig.getString("server_itemtype")); + jsonServerConfig.put("serial", serverConfig.getString("server_custom_asset_serial")); + + AgentLog.e("EMM - Receive the following configuration '" + jsonServerConfig.toString()); + + JSONObject local_server = preferences.loadJSONObject(serverConfig.getString("server_url")); + AgentLog.e("EMM - Try to load '" + serverConfig.getString("server_url") + "' server if exist"); + AgentLog.e("EMM - Found '" + local_server.toString() + "'"); + AgentLog.e("EMM - Exist ? -> '" + !local_server.toString().equals("{}") + "'"); + + if (local_server.toString().equals("{}")) { + ArrayList serverArray = preferences.loadServer(); + serverArray.add(serverConfig.getString("server_url")); + preferences.saveServer(serverArray); + preferences.saveJSONObject(serverConfig.getString("server_url"), jsonServerConfig); + enterpriseFeedback(getApplicationContext(), "server_url", "server_url added successfully", serverConfig.getString("server_url"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_tag", "server_tag added successfully", serverConfig.getString("server_tag"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_login", "server_login added successfully", serverConfig.getString("server_login"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_password", "server_password added successfully", "***", KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_itemtype", "server_itemtype added successfully", serverConfig.getString("server_itemtype"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_custom_asset_serial", "server_custom_asset_serial added successfully", serverConfig.getString("server_custom_asset_serial"), KeyedAppState.SEVERITY_INFO); + AgentLog.e("EMM - Server added successfully"); + } else { + preferences.deletePreferences(serverConfig.getString("server_url")); + preferences.saveJSONObject(serverConfig.getString("server_url"), jsonServerConfig); + enterpriseFeedback(getApplicationContext(), "server_url", "server_url updated successfully", serverConfig.getString("server_url"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_tag", "server_tag updated successfully", serverConfig.getString("server_tag"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_login", "server_login updated successfully", serverConfig.getString("server_login"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_password", "server_password updated successfully", "***", KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_itemtype", "server_itemtype updated successfully", serverConfig.getString("server_itemtype"), KeyedAppState.SEVERITY_INFO); + enterpriseFeedback(getApplicationContext(), "server_custom_asset_serial", "server_custom_asset_serial updated successfully", serverConfig.getString("server_custom_asset_serial"), KeyedAppState.SEVERITY_INFO); + AgentLog.e("EMM - Server updated successfully"); + } + + } catch (JSONException e) { + enterpriseFeedback(getApplicationContext(), "server_url", "error while adding/updating server -> " + e.getMessage(), serverConfig.getString("server_url"), KeyedAppState.SEVERITY_ERROR); + AgentLog.e("EMM - error while adding/updating server"); + AgentLog.e("EMM - " + e.getMessage()); } } + } else { + AgentLog.e("EMM - 'server_configuration_list' key is empty"); } + AgentLog.e("EMM - END resolve restrictions"); + } + + public void scheduleJob() { + SharedPreferences customSharedPreference = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + String timeInventory = customSharedPreference.getString("timeInventory", "Week"); + + final JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); + final ComponentName name = new ComponentName(this, InventoryJobScheduler.class); + final JobInfo jobInfo = getJobInfo(InventoryJobScheduler.INVENTORY_JOB_ID, timeInventory, name); + + if(customSharedPreference.getBoolean("autoStartInventory", false)) { + if (!isAlreadyScheduled(jobScheduler, jobInfo)) { + if (jobScheduler.schedule(jobInfo) == JobScheduler.RESULT_SUCCESS) { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Scheduled job successfully!"); + } + } else { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Scheduled job already initialized"); + } + } else { + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : autoStartInventory disabled, cancel JobScheduler"); + if (isAlreadyScheduled(jobScheduler, jobInfo)) { + jobScheduler.cancel(InventoryJobScheduler.INVENTORY_JOB_ID); + } + } + } + + private boolean isAlreadyScheduled(JobScheduler jobScheduler, JobInfo jobInfo) { + boolean jobAlreadyScheduled = false; + for (JobInfo existingJob: jobScheduler.getAllPendingJobs()) { + // check if scheduler exist with same ID and same minimum latency + if (existingJob.getId() == jobInfo.getId() + && existingJob.getMinLatencyMillis() == jobInfo.getMinLatencyMillis()) { + jobAlreadyScheduled = true; + break; + } + } + return jobAlreadyScheduled; + } + + private JobInfo getJobInfo(final int id, final String timeInventory, final ComponentName name) { + + //default week + long interval = TimeUnit.DAYS.toMillis(7); + if (timeInventory.equals("Day")) { + interval = TimeUnit.DAYS.toMillis(1); + } else if (timeInventory.equals("Week")) { + interval = TimeUnit.DAYS.toMillis(7); + } else if (timeInventory.equals("Month")) { + interval = TimeUnit.DAYS.toMillis(30); + } + + AgentLog.d("GLPI-AGENT-JOBSCHEDULER : Alarm scheduled each " + timeInventory); + + JobInfo.Builder builder = new JobInfo.Builder(id, name) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setPersisted(true); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + builder.setMinimumLatency(interval); + } else { + builder.setPeriodic(interval); + } + + return builder.build(); } } diff --git a/app/src/main/java/org/glpi/inventory/agent/ui/FragmentHome.java b/app/src/main/java/org/glpi/inventory/agent/ui/FragmentHome.java index dc2da5c92..8ae5ecba2 100644 --- a/app/src/main/java/org/glpi/inventory/agent/ui/FragmentHome.java +++ b/app/src/main/java/org/glpi/inventory/agent/ui/FragmentHome.java @@ -67,8 +67,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa presenter = new HomePresenter(this); - presenter.doBindService(FragmentHome.this.getActivity()); - Button btn_run = v.findViewById(R.id.btn_run_inventory); btn_run.setOnClickListener(new View.OnClickListener() { @Override diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fcbc8140b..cec1fd94b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,6 +52,7 @@ No server found Crash report is disable, please enable to test it Select the format to share + Inventory is scheduled XML JSON