Commit 56cd3fa1 authored by Adrien Béraud's avatar Adrien Béraud

add log activity

Change-Id: I32221a0907a79b2492405ad015120ca2eace1a6e
parent 4c19cdc7
......@@ -100,12 +100,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="false" />
<activity
android:name=".client.LogsActivity"
android:label="@string/pref_logs_title"
android:theme="@style/AppTheme.Navigation"
/>
<activity
android:name=".client.HomeActivity"
android:configChanges="screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/AppTheme.Navigation"
android:windowSoftInputMode="adjustResize">
......@@ -139,14 +144,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
<meta-data android:name="android.app.shortcuts"
android:resource="@xml/shortcuts"/>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
android:name=".client.ShareActivity"
android:label="@string/title_share_with"
android:icon="@mipmap/ic_launcher"
android:label="@string/title_share_with"
android:parentActivityName=".client.HomeActivity"
android:theme="@style/AppTheme">
<intent-filter>
......@@ -164,10 +169,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity
android:name=".account.AccountWizardActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:theme="@style/AppThemeBase.Light"
android:icon="@mipmap/ic_launcher"
android:resizeableActivity="true"
android:windowSoftInputMode="adjustResize"/>
android:theme="@style/AppThemeBase.Light"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".client.RingtoneActivity"
android:configChanges="screenSize|screenLayout|smallestScreenSize"
......@@ -186,7 +191,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
......@@ -207,8 +212,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:foregroundServiceType="dataSync" />
<service
android:name=".services.LocationSharingService"
android:foregroundServiceType="location"
android:exported="false" />
android:exported="false"
android:foregroundServiceType="location" />
<activity
android:name=".client.CallActivity"
......@@ -280,8 +285,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:name=".client.ConversationActivity"
android:allowEmbedded="true"
android:configChanges="screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:parentActivityName=".client.HomeActivity"
android:resizeableActivity="true"
android:theme="@style/AppTheme.Fullscreen"
......@@ -293,34 +298,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<intent-filter>
<action android:name=".service.DRingService" />
</intent-filter>
</service>
<!-- AndroidTV section -->
</service> <!-- AndroidTV section -->
<activity
android:name=".tv.main.HomeActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Jami.Leanback.Main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="jamitv"
android:host="cx.ring"
android:path="/home" />
android:path="/home"
android:scheme="jamitv" />
</intent-filter>
</activity>
<receiver
android:name=".tv.main.ChannelActionHandler"
android:enabled="true"
android:exported="true">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<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_ADDED_TO_WATCH_NEXT" />
......@@ -330,30 +338,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity
android:name=".tv.account.TVAccountWizard"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" />
<activity
android:name=".tv.search.SearchActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Leanback" />
<activity
android:name=".tv.about.AboutActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Leanback" />
<activity
android:name=".tv.account.TVShareActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Ring.Leanback" />
<activity
android:name=".tv.call.TVCallActivity"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:resizeableActivity="true"
android:showOnLockScreen="true"
android:supportsPictureInPicture="true"
......@@ -366,9 +374,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</activity>
<activity
android:name=".tv.camera.CustomCameraActivity"
android:theme="@style/AppTheme"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher">
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="cx.ring.action.CALL" />
......@@ -377,20 +385,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</activity>
<activity
android:name=".tv.contact.TVContactActivity"
android:theme="@style/Theme.Leanback.Details"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher">
android:theme="@style/Theme.Leanback.Details">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="jamitv"
android:host="cx.ring"
android:pathPrefix="/conversation/" />
android:pathPrefix="/conversation/"
android:scheme="jamitv" />
</intent-filter>
</activity>
<activity
android:name=".tv.account.TVSettingsActivity"
android:theme="@style/LeanbackPreferences" />
......@@ -408,8 +417,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity
android:name=".client.MediaViewerActivity"
android:exported="false"
android:label="@string/title_media_viewer"
android:icon="@mipmap/ic_launcher"
android:label="@string/title_media_viewer"
android:theme="@style/AppThemeBase.Dark" />
<service
......@@ -419,16 +428,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<activity
android:name=".client.ContactDetailsActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="@string/conversation_details"
android:icon="@mipmap/ic_launcher"
android:label="@string/conversation_details"
android:resizeableActivity="true"
android:theme="@style/AppTheme.Fullscreen"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".client.ConversationSelectionActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="Choose a contact or conversation"
android:icon="@mipmap/ic_launcher"
android:label="Choose a contact or conversation"
android:theme="@style/Theme.MaterialComponents.DayNight.Dialog.Alert"
android:windowSoftInputMode="adjustResize" />
</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;
import cx.ring.client.ContactDetailsActivity;
import cx.ring.client.ConversationSelectionActivity;
import cx.ring.client.HomeActivity;
import cx.ring.client.LogsActivity;
import cx.ring.client.RingtoneActivity;
import cx.ring.contactrequests.BlockListFragment;
import cx.ring.contactrequests.ContactRequestsFragment;
......@@ -232,4 +233,7 @@ public interface JamiInjectionComponent {
void inject(LinkDeviceFragment linkDeviceFragment);
void inject(ContactPickerFragment contactPickerFragment);
void inject(LogsActivity logsActivity);
}
......@@ -20,10 +20,9 @@
package cx.ring.settings;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.ArrayRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
......@@ -43,6 +42,7 @@ import android.widget.Toast;
import cx.ring.R;
import cx.ring.application.JamiApplication;
import cx.ring.client.HomeActivity;
import cx.ring.client.LogsActivity;
import cx.ring.databinding.FragSettingsBinding;
import net.jami.daemon.JamiService;
......@@ -142,18 +142,15 @@ public class SettingsFragment extends BaseSupportFragment<SettingsPresenter> imp
binding.settingsNotification.setOnClickListener(v -> new MaterialAlertDialogBuilder(view.getContext())
.setTitle(getString(R.string.pref_notification_title))
.setSingleChoiceItems(singleItems, mNotificationVisibility, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
checkedItem[0] = i;
}
})
.setSingleChoiceItems(singleItems, mNotificationVisibility, (dialogInterface, i) -> checkedItem[0] = i)
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
mNotificationVisibility = checkedItem[0];
saveSettings();
})
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {})
.show());
binding.settingsLogs.setOnClickListener(v -> startActivity(new Intent(v.getContext(), LogsActivity.class)));
}
@Override
......
......@@ -295,6 +295,14 @@ public class AndroidFileUtils {
// Save a file: path for use with ACTION_VIEW intents
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
......
<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/>.
android:layout_toEndOf="@id/theme_image"
android:layout_below="@id/theme_title" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_dark_theme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -165,7 +165,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout>
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_plugins_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -285,7 +285,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout>
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_typing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -336,7 +336,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</LinearLayout>
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/settings_read"