Skip to content

Commit

Permalink
Added extra options
Browse files Browse the repository at this point in the history
- Encrypted and plaintext (xml) backup / restore.
- Removed apk expire.
- Import unencrypted WhatsApp database.
- Choose between passphrase protection and the Android screenlock.
- Choice for the backup location: for Android 4 - 10, internal or removable storage; for Android 11+ any directory can be chosen.
- Set the maptype in the place picker.
- Option to treat view-once media as normal media.
- Option to ignore remote deletion.
- Choose between FCM or websocket notification delivery.
- Option to delete only the media from a message, not the rest of the message.
- Removed forward limit.
- Enabled internal preferences. Use at your own risk.
- Added options to select who can add you to a group.
  • Loading branch information
johanw666 committed Aug 6, 2024
1 parent c2bdac8 commit d96ddd9
Show file tree
Hide file tree
Showing 122 changed files with 5,107 additions and 107 deletions.
49 changes: 42 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Signal Android
# Signal Android

Signal is a simple, powerful, and secure messenger.
Signal is a messaging app for simple private communication with friends.

Signal uses your phone's data connection (WiFi/3G/4G/5G) to communicate securely. Millions of people use Signal every day for free and instantaneous communication anywhere in the world. Send and receive high-fidelity messages, participate in HD voice/video calls, and explore a growing set of new features that help you stay connected. Signal’s advanced privacy-preserving technology is always enabled, so you can focus on sharing the moments that matter with the people who matter to you.
Signal uses your phone's data connection (WiFi/3G/4G) to communicate securely, optionally supports plain SMS/MMS to function as a unified messenger, and can also encrypt the stored messages on your phone.

Currently available on the Play Store and [signal.org](https://signal.org/android/apk/).
Currently available on the Play store and [signal.org](https://signal.org/android/apk/).

<a href='https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80px'/></a>

Expand All @@ -18,17 +18,52 @@ Want to live life on the bleeding edge and help out with testing?

You can subscribe to Signal Android Beta releases here:
https://play.google.com/apps/testing/org.thoughtcrime.securesms

If you're interested in a life of peace and tranquility, stick with the standard releases.

## Contributing Translations
Interested in helping to translate Signal? Contribute here:

https://www.transifex.com/projects/p/signal-android/

## Contributing Code

If you're new to the Signal codebase, we recommend going through our issues and picking out a simple bug to fix (check the "easy" label in our issues) in order to get yourself familiar. Also please have a look at the [CONTRIBUTING.md](https://github.com/signalapp/Signal-Android/blob/main/CONTRIBUTING.md), that might answer some of your questions.

For larger changes and feature ideas, we ask that you propose it on the [unofficial Community Forum](https://community.signalusers.org) for a high-level discussion with the wider community before implementation.

## Contributing Ideas
Have something you want to say about Signal projects or want to be part of the conversation? Get involved in the [community forum](https://community.signalusers.org).
Have something you want to say about Open Whisper Systems projects or want to be part of the conversation? Get involved in the [community forum](https://community.signalusers.org).

## WhatsApp Data Import

This is based on code contributed by Samuel Welten (https://github.com/jukefoxer/Signal-Android) and Wollwolke
(https://github.com/Wollwolke/Signal-Android/tree/feature/wa-db-import). Thank you both for this.

This fork of the Signal App provides a method to import one's WhatsApp conversations. It's currently still a pretty tedious process, but at least it's possible.

### What works

* Import 1-to-1 text conversation threads.
* Import group chat conversations if a group chat with the same name is set up in the Signal App.
* Importing images and videos messages from WhatsApp chats.

### What doesn't work

* Multimedia messages other than images and videos are currently not imported.
* It's pretty slow (10 seconds per 1000 messages).

### How to do it

* Extract your unencrypted msgstore.db from your WhatsApp installation. There are several methods to do so. WhatsAppDump seems to offer a possibility that doesn't require rooting the device. A more detailed description of how to do so might be added here in the future.
* Copy the msgstore.db file to the top level directory of your internal storage
* Make an encrypted Backup of your Signal Messages using the built-in feature of the Signal App.
* Build and install this version of the Signal App and import the encrypted Backup of your signal messages.
* You might have to go to the app permission settings and give it the permission to manage all of the external storage.
* Go to Backup => Import WhatsApp to start the import.
* Be patient until it finishes.
* If you're happy with the WhatsApp import create another encrypted backup of all Signal messages.
* Install the original Signal app again and import the encrypted Backup.

Help
====
Expand All @@ -54,7 +89,7 @@ The form and manner of this distribution makes it eligible for export under the

## License

Copyright 2013-2024 Signal Messenger, LLC
Copyright 2013-2023 Signal

Licensed under the GNU AGPLv3: https://www.gnu.org/licenses/agpl-3.0.html

Expand Down
44 changes: 24 additions & 20 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,19 @@ plugins {
apply(from = "static-ips.gradle.kts")

val canonicalVersionCode = 1443
val canonicalVersionName = "7.13.3"
val canonicalVersionName = "7.13.3.0-JW"
val currentHotfixVersion = 0
val maxHotfixVersions = 100

// JW: re-added
val abiPostFix: Map<String, Int> = mapOf(
"universal" to 0,
"armeabi-v7a" to 1,
"arm64-v8a" to 2,
"x86" to 3,
"x86_64" to 4
)

val keystores: Map<String, Properties?> = mapOf("debug" to loadKeystoreProperties("keystore.debug.properties"))

val selectableVariants = listOf(
Expand Down Expand Up @@ -164,8 +173,8 @@ android {

manifestPlaceholders["mapsKey"] = "AIzaSyCSx9xea86GwDKGznCAULE9Y5a8b-TfN9U"

buildConfigField("long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L")
buildConfigField("String", "GIT_HASH", "\"${getGitHash()}\"")
buildConfigField("long", "BUILD_TIMESTAMP", "1000L") // JW: fixed time for reproducible builds, is not used anyway
buildConfigField("String", "GIT_HASH", "\"000000\"") // JW
buildConfigField("String", "SIGNAL_URL", "\"https://chat.signal.org\"")
buildConfigField("String", "STORAGE_URL", "\"https://storage.signal.org\"")
buildConfigField("String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\"")
Expand Down Expand Up @@ -272,6 +281,7 @@ android {
getByName("release") {
isMinifyEnabled = true
proguardFiles(*buildTypes["debug"].proguardFiles.toTypedArray())
manifestPlaceholders["mapsKey"] = getMapsKey() // JW
buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Release\"")
}

Expand Down Expand Up @@ -401,24 +411,17 @@ android {
outputs
.map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl }
.forEach { output ->
if (output.baseName.contains("nightly")) {
var tag = getCurrentGitTag()
if (!tag.isNullOrEmpty()) {
if (tag.startsWith("v")) {
tag = tag.substring(1)
}
output.versionNameOverride = tag
output.outputFileName = output.outputFileName.replace(".apk", "-${output.versionNameOverride}.apk")
} else {
output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk")
}
} else {
output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk")

if (currentHotfixVersion >= maxHotfixVersions) {
throw AssertionError("Hotfix version is too large!")
}
// JW: rewrote section
output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk")

val abiName: String = output.getFilter("ABI") ?: "universal"
val postFix: Int = abiPostFix[abiName]!!

if (postFix >= maxHotfixVersions) {
throw AssertionError("maxHotfixVersions is too large")
}

output.versionCodeOverride = canonicalVersionCode * maxHotfixVersions + postFix
}
}

Expand Down Expand Up @@ -464,6 +467,7 @@ dependencies {
implementation(project(":photoview"))
implementation(project(":core-ui"))

implementation("net.lingala.zip4j:zip4j:2.11.5") // JW: added
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.appcompat) {
version {
Expand Down
19 changes: 17 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<!-- JW: override for Android 10. For Android 11 and up we use the MANAGE_EXTERNAL_STORAGE permission. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.CAMERA" />

Expand Down Expand Up @@ -95,6 +96,10 @@
android:theme="@style/TextSecure.LightTheme"
android:largeHeap="true">

<!-- JW: added. This is currently only relevant for captchas. -->
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" />

<meta-data
android:name="com.google.android.gms.wallet.api.enabled"
android:value="true" />
Expand Down Expand Up @@ -659,12 +664,22 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"/>

<!-- JW: added the windowSoftInputMode="stateAlwaysVisible" flag here to show a keyboard on open -->
<activity android:name=".PassphrasePromptActivity"
android:launchMode="singleTask"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateAlwaysVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"/>

<!-- JW: Add activity used in plaintext backup import / export -->
<activity android:name=".ImportExportActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>

<!-- JW: Add activity used in encrypted backup import -->
<activity android:name=".ExitActivity"
android:theme="@android:style/Theme.NoDisplay" />

<activity android:name=".NewConversationActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static void onFirstEverAppLaunch(@NonNull Context context) {
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
TextSecurePreferences.setPasswordDisabled(context, true);
//TextSecurePreferences.setPasswordDisabled(context, true); // JW: don't do this
TextSecurePreferences.setReadReceiptsEnabled(context, true);
TextSecurePreferences.setTypingIndicatorsEnabled(context, true);
TextSecurePreferences.setHasSeenWelcomeScreen(context, false);
Expand Down Expand Up @@ -73,7 +73,7 @@ public static void onRepairFirstEverAppLaunch(@NonNull Context context) {
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
TextSecurePreferences.setPasswordDisabled(context, true);
//TextSecurePreferences.setPasswordDisabled(context, true); // JW: don't do this
AppDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch();
AppDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,15 @@ private void initializeFirstEverAppLaunch() {

Log.i(TAG, "Setting first install version to " + BuildConfig.CANONICAL_VERSION_CODE);
TextSecurePreferences.setFirstInstallVersion(this, BuildConfig.CANONICAL_VERSION_CODE);
// JW: this code bluntly removes the password setting and makes password protected installs crash.
/*
} else if (!TextSecurePreferences.isPasswordDisabled(this) && VersionTracker.getDaysSinceFirstInstalled(this) < 90) {
Log.i(TAG, "Detected a new install that doesn't have passphrases disabled -- assuming bad initialization.");
AppInitialization.onRepairFirstEverAppLaunch(this);
} else if (!TextSecurePreferences.isPasswordDisabled(this) && VersionTracker.getDaysSinceFirstInstalled(this) < 912) {
Log.i(TAG, "Detected a not-recent install that doesn't have passphrases disabled -- disabling now.");
TextSecurePreferences.setPasswordDisabled(this, true);
*/
}
}

Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/org/thoughtcrime/securesms/ExitActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.thoughtcrime.securesms;

import android.content.Intent;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;

public class ExitActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

if (Build.VERSION.SDK_INT >= 21) {
finishAndRemoveTask();
} else {
finish();
}

System.exit(0);
}

public static void exitAndRemoveFromRecentApps(Activity activity) {
Intent intent = new Intent(activity, ExitActivity.class);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_NO_ANIMATION);

activity.startActivity(intent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.thoughtcrime.securesms;

import android.os.Bundle;
import android.view.MenuItem;

import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;


public class ImportExportActivity extends PassphraseRequiredActivity {

@SuppressWarnings("unused")
private static final String TAG = ImportExportActivity.class.getSimpleName();

private DynamicTheme dynamicTheme = new DynamicTheme();
private DynamicLanguage dynamicLanguage = new DynamicLanguage();

@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
}

@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initFragment(android.R.id.content, new ImportExportFragment(), dynamicLanguage.getCurrentLocale());
}

@Override
public void onResume() {
dynamicTheme.onResume(this);
super.onResume();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);

switch (item.getItemId()) {
case android.R.id.home: finish(); return true;
}

return false;
}
}
Loading

0 comments on commit d96ddd9

Please sign in to comment.