Skip to content
Snippets Groups Projects
Commit 56cd3fa1 authored by Adrien Béraud's avatar Adrien Béraud
Browse files

add log activity

Change-Id: I32221a0907a79b2492405ad015120ca2eace1a6e
parent 4c19cdc7
No related branches found
No related tags found
No related merge requests found
Showing
with 466 additions and 58 deletions
...@@ -100,12 +100,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -100,12 +100,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<meta-data <meta-data
android:name="google_analytics_adid_collection_enabled" android:name="google_analytics_adid_collection_enabled"
android:value="false" /> android:value="false" />
<activity
android:name=".client.LogsActivity"
android:label="@string/pref_logs_title"
android:theme="@style/AppTheme.Navigation"
/>
<activity <activity
android:name=".client.HomeActivity" android:name=".client.HomeActivity"
android:configChanges="screenSize|screenLayout|smallestScreenSize" android:configChanges="screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@style/AppTheme.Navigation" android:theme="@style/AppTheme.Navigation"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
...@@ -139,14 +144,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -139,14 +144,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<meta-data <meta-data
android:name="android.app.searchable" android:name="android.app.searchable"
android:resource="@xml/searchable" /> android:resource="@xml/searchable" />
<meta-data
<meta-data android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" /> android:resource="@xml/shortcuts" />
</activity> </activity>
<activity <activity
android:name=".client.ShareActivity" android:name=".client.ShareActivity"
android:label="@string/title_share_with"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/title_share_with"
android:parentActivityName=".client.HomeActivity" android:parentActivityName=".client.HomeActivity"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<intent-filter> <intent-filter>
...@@ -164,9 +169,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -164,9 +169,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity <activity
android:name=".account.AccountWizardActivity" android:name=".account.AccountWizardActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:theme="@style/AppThemeBase.Light"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:resizeableActivity="true" android:resizeableActivity="true"
android:theme="@style/AppThemeBase.Light"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".client.RingtoneActivity" android:name=".client.RingtoneActivity"
...@@ -207,8 +212,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -207,8 +212,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:foregroundServiceType="dataSync" /> android:foregroundServiceType="dataSync" />
<service <service
android:name=".services.LocationSharingService" android:name=".services.LocationSharingService"
android:foregroundServiceType="location" android:exported="false"
android:exported="false" /> android:foregroundServiceType="location" />
<activity <activity
android:name=".client.CallActivity" android:name=".client.CallActivity"
...@@ -280,8 +285,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -280,8 +285,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:name=".client.ConversationActivity" android:name=".client.ConversationActivity"
android:allowEmbedded="true" android:allowEmbedded="true"
android:configChanges="screenSize|screenLayout|smallestScreenSize" android:configChanges="screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:parentActivityName=".client.HomeActivity" android:parentActivityName=".client.HomeActivity"
android:resizeableActivity="true" android:resizeableActivity="true"
android:theme="@style/AppTheme.Fullscreen" android:theme="@style/AppTheme.Fullscreen"
...@@ -293,34 +298,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -293,34 +298,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<intent-filter> <intent-filter>
<action android:name=".service.DRingService" /> <action android:name=".service.DRingService" />
</intent-filter> </intent-filter>
</service> </service> <!-- AndroidTV section -->
<!-- AndroidTV section -->
<activity <activity
android:name=".tv.main.HomeActivity" android:name=".tv.main.HomeActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Jami.Leanback.Main"> android:theme="@style/Theme.Jami.Leanback.Main">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data <data
android:scheme="jamitv"
android:host="cx.ring" android:host="cx.ring"
android:path="/home" /> android:path="/home"
android:scheme="jamitv" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver <receiver
android:name=".tv.main.ChannelActionHandler" android:name=".tv.main.ChannelActionHandler"
android:enabled="true" android:enabled="true"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<action android:name="android.media.tv.ACTION_INITIALIZE_PROGRAMS" /> <action android:name="android.media.tv.ACTION_INITIALIZE_PROGRAMS" />
<action android:name="android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED" /> <action android:name="android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
<action android:name="android.media.tv.ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" /> <action android:name="android.media.tv.ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" />
...@@ -330,30 +338,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -330,30 +338,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity <activity
android:name=".tv.account.TVAccountWizard" android:name=".tv.account.TVAccountWizard"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity <activity
android:name=".tv.search.SearchActivity" android:name=".tv.search.SearchActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Leanback" /> android:theme="@style/Theme.Leanback" />
<activity <activity
android:name=".tv.about.AboutActivity" android:name=".tv.about.AboutActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Leanback" /> android:theme="@style/Theme.Leanback" />
<activity <activity
android:name=".tv.account.TVShareActivity" android:name=".tv.account.TVShareActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Ring.Leanback" /> android:theme="@style/Theme.Ring.Leanback" />
<activity <activity
android:name=".tv.call.TVCallActivity" android:name=".tv.call.TVCallActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:resizeableActivity="true" android:resizeableActivity="true"
android:showOnLockScreen="true" android:showOnLockScreen="true"
android:supportsPictureInPicture="true" android:supportsPictureInPicture="true"
...@@ -366,9 +374,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -366,9 +374,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</activity> </activity>
<activity <activity
android:name=".tv.camera.CustomCameraActivity" android:name=".tv.camera.CustomCameraActivity"
android:theme="@style/AppTheme" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"> android:theme="@style/AppTheme">
<intent-filter> <intent-filter>
<action android:name="cx.ring.action.CALL" /> <action android:name="cx.ring.action.CALL" />
...@@ -377,20 +385,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -377,20 +385,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</activity> </activity>
<activity <activity
android:name=".tv.contact.TVContactActivity" android:name=".tv.contact.TVContactActivity"
android:theme="@style/Theme.Leanback.Details" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"> android:theme="@style/Theme.Leanback.Details">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data <data
android:scheme="jamitv"
android:host="cx.ring" android:host="cx.ring"
android:pathPrefix="/conversation/" /> android:pathPrefix="/conversation/"
android:scheme="jamitv" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".tv.account.TVSettingsActivity" android:name=".tv.account.TVSettingsActivity"
android:theme="@style/LeanbackPreferences" /> android:theme="@style/LeanbackPreferences" />
...@@ -408,8 +417,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -408,8 +417,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity <activity
android:name=".client.MediaViewerActivity" android:name=".client.MediaViewerActivity"
android:exported="false" android:exported="false"
android:label="@string/title_media_viewer"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/title_media_viewer"
android:theme="@style/AppThemeBase.Dark" /> android:theme="@style/AppThemeBase.Dark" />
<service <service
...@@ -419,16 +428,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -419,16 +428,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity <activity
android:name=".client.ContactDetailsActivity" android:name=".client.ContactDetailsActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="@string/conversation_details"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/conversation_details"
android:resizeableActivity="true" android:resizeableActivity="true"
android:theme="@style/AppTheme.Fullscreen" android:theme="@style/AppTheme.Fullscreen"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".client.ConversationSelectionActivity" android:name=".client.ConversationSelectionActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="Choose a contact or conversation"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="Choose a contact or conversation"
android:theme="@style/Theme.MaterialComponents.DayNight.Dialog.Alert" android:theme="@style/Theme.MaterialComponents.DayNight.Dialog.Alert"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
</application> </application>
......
/*
* Copyright (C) 2004-2021 Savoir-faire Linux Inc.
*
* Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
*
* This program 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.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cx.ring.client;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import com.google.android.material.snackbar.Snackbar;
import net.jami.services.HardwareService;
import net.jami.utils.StringUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.inject.Inject;
import javax.inject.Singleton;
import cx.ring.R;
import cx.ring.application.JamiApplication;
import cx.ring.databinding.ActivityLogsBinding;
import cx.ring.utils.AndroidFileUtils;
import cx.ring.utils.ContentUriHandler;
import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class LogsActivity extends AppCompatActivity {
private static final String TAG = LogsActivity.class.getSimpleName();
private ActivityLogsBinding binding;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
private Disposable disposable;
private ActivityResultLauncher<String> fileSaver;
private File mCurrentFile = null;
@Inject
@Singleton
HardwareService mHardwareService;
public LogsActivity() {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
JamiApplication.getInstance().startDaemon();
JamiApplication.getInstance().getInjectionComponent().inject(this);
binding = ActivityLogsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar ab = getSupportActionBar();
if (ab != null)
ab.setDisplayHomeAsUpEnabled(true);
fileSaver = registerForActivityResult(new ActivityResultContracts.CreateDocument(), result -> compositeDisposable.add(
AndroidFileUtils.copyFileToUri(getContentResolver(), mCurrentFile, result).
observeOn(AndroidSchedulers.mainThread()).
subscribe(() -> {
if (!mCurrentFile.delete())
Log.w(TAG, "Can't delete temp file");
mCurrentFile = null;
Snackbar.make(binding.getRoot(), R.string.file_saved_successfully, Snackbar.LENGTH_SHORT).show();
}, error -> Snackbar.make(binding.getRoot(), R.string.generic_error, Snackbar.LENGTH_SHORT).show())));
binding.fab.setOnClickListener(view -> {
if (disposable == null)
startLogging();
else
stopLogging();
});
if (mHardwareService.isLogging())
startLogging();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.logs_menu, menu);
return super.onCreateOptionsMenu(menu);
}
private Maybe<String> getLog() {
if (mHardwareService.isLogging())
return mHardwareService.startLogs()
.firstElement();
CharSequence log = binding.logView.getText();
if (StringUtils.isEmpty(log))
return Maybe.empty();
return Maybe.just(log.toString());
}
private Maybe<File> getLogFile() {
return getLog()
.observeOn(Schedulers.io())
.map(log -> {
File file = AndroidFileUtils.createLogFile(this);
OutputStream os = new FileOutputStream(file);
os.write(log.getBytes());
return file;
});
}
private Maybe<Uri> getLogUri() {
return getLogFile().map(file -> ContentUriHandler.getUriForFile(this, ContentUriHandler.AUTHORITY_FILES, file));
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
finish();
return true;
} else if (id == R.id.menu_log_share) {
compositeDisposable.add(getLogUri()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(uri -> {
Log.w(TAG, "saved logs to " + uri);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
String type = getContentResolver().getType(uri);
sendIntent.setDataAndType(uri, type);
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(sendIntent, null));
}, e -> Snackbar.make(binding.getRoot(), "Error sharing logs: " + e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show()));
return true;
} else if (id == R.id.menu_log_save) {
compositeDisposable.add(getLogFile()
.subscribe(file -> {
mCurrentFile = file;
fileSaver.launch(file.getName());
}));
return true;
}
return super.onOptionsItemSelected(item);
}
void startLogging() {
binding.logView.setText("");
disposable = mHardwareService.startLogs()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
binding.logView.setText(message);
binding.scroll.post(() -> binding.scroll.fullScroll(View.FOCUS_DOWN));
}, e -> Log.w(TAG, "Error in logger", e));
compositeDisposable.add(disposable);
setButtonState(true);
}
void stopLogging() {
disposable.dispose();
disposable = null;
mHardwareService.stopLogs();
setButtonState(false);
}
void setButtonState(boolean logging) {
binding.fab.setText(logging ? R.string.pref_logs_stop : R.string.pref_logs_start);
binding.fab.setBackgroundColor(ContextCompat.getColor(this, logging ? R.color.red_400 : R.color.colorSecondary));
}
@Override
protected void onDestroy() {
if (disposable != null) {
disposable.dispose();
disposable = null;
}
compositeDisposable.clear();
super.onDestroy();
}
}
\ No newline at end of file
...@@ -41,6 +41,7 @@ import cx.ring.application.JamiApplication; ...@@ -41,6 +41,7 @@ import cx.ring.application.JamiApplication;
import cx.ring.client.ContactDetailsActivity; import cx.ring.client.ContactDetailsActivity;
import cx.ring.client.ConversationSelectionActivity; import cx.ring.client.ConversationSelectionActivity;
import cx.ring.client.HomeActivity; import cx.ring.client.HomeActivity;
import cx.ring.client.LogsActivity;
import cx.ring.client.RingtoneActivity; import cx.ring.client.RingtoneActivity;
import cx.ring.contactrequests.BlockListFragment; import cx.ring.contactrequests.BlockListFragment;
import cx.ring.contactrequests.ContactRequestsFragment; import cx.ring.contactrequests.ContactRequestsFragment;
...@@ -232,4 +233,7 @@ public interface JamiInjectionComponent { ...@@ -232,4 +233,7 @@ public interface JamiInjectionComponent {
void inject(LinkDeviceFragment linkDeviceFragment); void inject(LinkDeviceFragment linkDeviceFragment);
void inject(ContactPickerFragment contactPickerFragment); void inject(ContactPickerFragment contactPickerFragment);
void inject(LogsActivity logsActivity);
} }
...@@ -20,10 +20,9 @@ ...@@ -20,10 +20,9 @@
package cx.ring.settings; package cx.ring.settings;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.ArrayRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
...@@ -43,6 +42,7 @@ import android.widget.Toast; ...@@ -43,6 +42,7 @@ import android.widget.Toast;
import cx.ring.R; import cx.ring.R;
import cx.ring.application.JamiApplication; import cx.ring.application.JamiApplication;
import cx.ring.client.HomeActivity; import cx.ring.client.HomeActivity;
import cx.ring.client.LogsActivity;
import cx.ring.databinding.FragSettingsBinding; import cx.ring.databinding.FragSettingsBinding;
import net.jami.daemon.JamiService; import net.jami.daemon.JamiService;
...@@ -142,18 +142,15 @@ public class SettingsFragment extends BaseSupportFragment<SettingsPresenter> imp ...@@ -142,18 +142,15 @@ public class SettingsFragment extends BaseSupportFragment<SettingsPresenter> imp
binding.settingsNotification.setOnClickListener(v -> new MaterialAlertDialogBuilder(view.getContext()) binding.settingsNotification.setOnClickListener(v -> new MaterialAlertDialogBuilder(view.getContext())
.setTitle(getString(R.string.pref_notification_title)) .setTitle(getString(R.string.pref_notification_title))
.setSingleChoiceItems(singleItems, mNotificationVisibility, new DialogInterface.OnClickListener() { .setSingleChoiceItems(singleItems, mNotificationVisibility, (dialogInterface, i) -> checkedItem[0] = i)
@Override
public void onClick(DialogInterface dialogInterface, int i) {
checkedItem[0] = i;
}
})
.setPositiveButton(android.R.string.ok, (dialog, id) -> { .setPositiveButton(android.R.string.ok, (dialog, id) -> {
mNotificationVisibility = checkedItem[0]; mNotificationVisibility = checkedItem[0];
saveSettings(); saveSettings();
}) })
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {}) .setNegativeButton(android.R.string.cancel, (dialog, id) -> {})
.show()); .show());
binding.settingsLogs.setOnClickListener(v -> startActivity(new Intent(v.getContext(), LogsActivity.class)));
} }
@Override @Override
......
...@@ -295,6 +295,14 @@ public class AndroidFileUtils { ...@@ -295,6 +295,14 @@ public class AndroidFileUtils {
// Save a file: path for use with ACTION_VIEW intents // Save a file: path for use with ACTION_VIEW intents
return File.createTempFile(imageFileName, ".webm", getTempShareDir(context)); return File.createTempFile(imageFileName, ".webm", getTempShareDir(context));
} }
public static File createLogFile(@NonNull Context context) throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
String imageFileName = "log_" + timeStamp + "_";
// Save a file: path for use with ACTION_VIEW intents
return File.createTempFile(imageFileName, ".log", getTempShareDir(context));
}
/** /**
* Copies a file from a uri whether locally on a remote location to the local cache * Copies a file from a uri whether locally on a remote location to the local cache
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM14,17L7,17v-2h7v2zM17,13L7,13v-2h10v2zM17,9L7,9L7,7h10v2z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".client.LogsActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/background"
tools:menu="@menu/logs_menu"
tools:title="Logs"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:id="@+id/log_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/padding_medium"
android:textIsSelectable="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:text="@tools:sample/lorem/random" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="@dimen/fab_margin"
android:gravity="center"
android:text="@string/pref_logs_start"
app:icon="@drawable/baseline_article_24" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
...@@ -71,7 +71,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -71,7 +71,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:layout_toEndOf="@id/theme_image" android:layout_toEndOf="@id/theme_image"
android:layout_below="@id/theme_title" /> android:layout_below="@id/theme_title" />
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_dark_theme" android:id="@+id/settings_dark_theme"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -165,7 +165,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -165,7 +165,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_plugins_switch" android:id="@+id/settings_plugins_switch"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -285,7 +285,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -285,7 +285,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_typing" android:id="@+id/settings_typing"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -336,7 +336,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -336,7 +336,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_read" android:id="@+id/settings_read"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -387,7 +387,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -387,7 +387,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_block_record" android:id="@+id/settings_block_record"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -525,7 +525,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -525,7 +525,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_push_notifications" android:id="@+id/settings_push_notifications"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -575,7 +575,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -575,7 +575,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_place_call" android:id="@+id/settings_place_call"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -625,7 +625,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -625,7 +625,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_startup" android:id="@+id/settings_startup"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -675,7 +675,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -675,7 +675,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout> </LinearLayout>
<Switch <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_persistNotification" android:id="@+id/settings_persistNotification"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -686,6 +686,56 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -686,6 +686,56 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</RelativeLayout> </RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="@string/pref_category_diagnostic"
android:textColor="@color/textColorAccent"
android:textSize="18sp"
android:layout_marginStart="64dp" />
<RelativeLayout
android:id="@+id/settings_logs"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/padding_large">
<ImageView
android:id="@+id/system_diagnostics_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/pref_persistNotification_summary"
android:src="@drawable/baseline_article_24"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="32dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/system_diagnostics_image"
android:orientation="vertical">
<TextView
style="@style/ListPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="@string/pref_logs_title" />
<TextView
style="@style/ListSecondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pref_logs_summary" />
</LinearLayout>
</RelativeLayout>
</LinearLayout> </LinearLayout>
</cx.ring.views.BoundedScrollView> </cx.ring.views.BoundedScrollView>
</RelativeLayout> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".client.HomeActivity">
<item
android:id="@+id/menu_log_share"
android:icon="@drawable/baseline_share_24"
android:title="@string/share_label"
app:showAsAction="collapseActionView|always" />
<item
android:id="@+id/menu_log_save"
android:icon="@drawable/baseline_file_download_24"
android:title="@string/dial_number"
app:showAsAction="always" />
</menu>
\ No newline at end of file
...@@ -19,13 +19,6 @@ ...@@ -19,13 +19,6 @@
android:visible="false" android:visible="false"
app:showAsAction="always" /> app:showAsAction="always" />
<!--
Created by Rohith M S from Noun Project
Licensed under Creative Commons :
http://creativecommons.org/licenses/by/3.0/us/legalcode
Used without any modification.
-->
<item <item
android:id="@+id/menu_overflow" android:id="@+id/menu_overflow"
android:orderInCategory="101" android:orderInCategory="101"
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<string name="pref_category_video">Video</string> <string name="pref_category_video">Video</string>
<string name="pref_category_system">System</string> <string name="pref_category_system">System</string>
<string name="pref_category_privacy">Privacy</string> <string name="pref_category_privacy">Privacy</string>
<string name="pref_category_diagnostic">Diagnostics</string>
<string name="pref_mobileData_title">Mobile data</string> <string name="pref_mobileData_title">Mobile data</string>
<string name="pref_mobileData_summary">Allow Jami on 3G/LTE networks additionally to Wi-Fi</string> <string name="pref_mobileData_summary">Allow Jami on 3G/LTE networks additionally to Wi-Fi</string>
...@@ -53,6 +54,11 @@ ...@@ -53,6 +54,11 @@
<string name="pref_persistNotification_title">Run in background</string> <string name="pref_persistNotification_title">Run in background</string>
<string name="pref_persistNotification_summary">Allow running in background to receive calls and messages.</string> <string name="pref_persistNotification_summary">Allow running in background to receive calls and messages.</string>
<string name="pref_logs_title">Diagnostic logs</string>
<string name="pref_logs_summary">Open diagnostic log settings</string>
<string name="pref_logs_start">Start Logging</string>
<string name="pref_logs_stop">Stop logging</string>
<string name="pref_typing_title">Enable typing indicators</string> <string name="pref_typing_title">Enable typing indicators</string>
<string name="pref_typing_summary">Send and receive typing indicators showing that a message is being typed.</string> <string name="pref_typing_summary">Send and receive typing indicators showing that a message is being typed.</string>
......
...@@ -248,6 +248,11 @@ public class DaemonService { ...@@ -248,6 +248,11 @@ public class DaemonService {
public void contactRemoved(String accountId, String uri, boolean banned) { public void contactRemoved(String accountId, String uri, boolean banned) {
mExecutor.submit(() -> mAccountService.contactRemoved(accountId, uri, banned)); mExecutor.submit(() -> mAccountService.contactRemoved(accountId, uri, banned));
} }
@Override
public void messageSend(String message) {
mHardwareService.logMessage(message);
}
} }
class DaemonCallAndConferenceCallback extends Callback { class DaemonCallAndConferenceCallback extends Callback {
......
...@@ -23,6 +23,7 @@ package net.jami.services; ...@@ -23,6 +23,7 @@ package net.jami.services;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
...@@ -34,10 +35,14 @@ import net.jami.daemon.UintVect; ...@@ -34,10 +35,14 @@ import net.jami.daemon.UintVect;
import net.jami.model.Conference; import net.jami.model.Conference;
import net.jami.model.Call; import net.jami.model.Call;
import net.jami.utils.Log; import net.jami.utils.Log;
import net.jami.utils.StringUtils;
import net.jami.utils.Tuple; import net.jami.utils.Tuple;
import io.reactivex.Completable; import io.reactivex.Completable;
import io.reactivex.Emitter;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Scheduler; import io.reactivex.Scheduler;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject; import io.reactivex.subjects.BehaviorSubject;
import io.reactivex.subjects.PublishSubject; import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject; import io.reactivex.subjects.Subject;
...@@ -209,4 +214,52 @@ public abstract class HardwareService { ...@@ -209,4 +214,52 @@ public abstract class HardwareService {
public abstract void setDeviceOrientation(int rotation); public abstract void setDeviceOrientation(int rotation);
protected abstract List<String> getVideoDevices(); protected abstract List<String> getVideoDevices();
private Observable<String> logs = null;
private Emitter<String> logEmitter = null;
synchronized public boolean isLogging() {
return logs != null;
}
synchronized public Observable<String> startLogs() {
if (logs == null) {
logs = Observable.create((ObservableOnSubscribe<String>) emitter -> {
Log.w(TAG, "ObservableOnSubscribe JamiService.monitor(true)");
logEmitter = emitter;
JamiService.monitor(true);
emitter.setCancellable(() -> {
Log.w(TAG, "ObservableOnSubscribe CANCEL JamiService.monitor(false)");
synchronized (HardwareService.this) {
JamiService.monitor(false);
logEmitter = null;
logs = null;
}
});
})
.observeOn(Schedulers.io())
.scan(new StringBuffer(1024), (sb, message) -> sb.append(message).append('\n'))
.throttleLatest(500, TimeUnit.MILLISECONDS)
.map(StringBuffer::toString)
.replay(1)
.autoConnect();
}
return logs;
}
synchronized public void stopLogs() {
if (logEmitter != null) {
Log.w(TAG, "stopLogs JamiService.monitor(false)");
JamiService.monitor(false);
logEmitter.onComplete();
logEmitter = null;
logs = null;
}
}
void logMessage(String message) {
if (logEmitter != null && !StringUtils.isEmpty(message)) {
logEmitter.onNext(message);
}
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment