Skip to content

Commit

Permalink
Update insights copy and queries.
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-signal committed Nov 15, 2019
1 parent 739fe58 commit 599bb5a
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 86 deletions.
2 changes: 1 addition & 1 deletion lint.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<issue id="HardcodedText" severity="error" />
<issue id="VectorRaster" severity="error" />
<issue id="ButtonOrder" severity="error" />
<issue id="ExtraTranslation" severity="error" />
<issue id="ExtraTranslation" severity="warning" />

<issue id="RestrictedApi" severity="error">
<ignore path="src/org/thoughtcrime/securesms/mediasend/camerax/VideoCapture.java" />
Expand Down
12 changes: 5 additions & 7 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1544,15 +1544,13 @@
<string name="Insights__percent">%</string>
<string name="Insights__title">Insights</string>
<string name="InsightsDashboardFragment__title">Insights</string>
<string name="InsightsDashboardFragment__tagline">%1$d%% of your outgoing messages in the past 7 days were end-to-end encrypted with Signal Protocol.</string>
<string name="InsightsDashboardFragment__boost_your_signal">Boost your Signal</string>
<string name="InsightsDashboardFragment__100_title">Your Signal is Strong</string>
<string name="InsightsDashboardFragment__no_signal_yet">No Signal (yet)</string>
<string name="InsightsDashboardFragment__youre_just_getting_started">You\'re just getting started. Insights will be displayed after you send a few messages.</string>
<string name="InsightsDashboardFragment__signal_protocol_automatically_protected">Signal Protocol automatically protected %1$d%% of your outgoing messages over the past %2$d days. Conversations between Signal users are always end-to-end encrypted.</string>
<string name="InsightsDashboardFragment__boost_your_signal">Signal boost</string>
<string name="InsightsDashboardFragment__not_enough_data">Not enough data</string>
<string name="InsightsDashboardFragment__your_insights_percentage_is_calculated_based_on">Your Insights percentage is calculated based on outgoing messages within the past %1$d days that have not disappeared or been deleted.</string>
<string name="InsightsDashboardFragment__start_a_conversation">Start a conversation</string>
<string name="InsightsDashboardFragment__100_description">Signal\'s advanced privacy-preserving technology automatically protected all of your recent outgoing messages.</string>
<string name="InsightsDashboardFragment__invite_your_contacts">Start communicating securely and enable new features that go beyond the limitations of unencrypted SMS messages by inviting more contacts to join Signal.</string>
<string name="InsightsDashboardFragment__this_stat_was_generated_locally">This stat was locally generated on your device and can only be seen by you. It is never transmitted anywhere.</string>
<string name="InsightsDashboardFragment__this_stat_was_generated_locally">These statistics were locally generated on your device and can only be seen by you. They are never transmitted anywhere.</string>
<string name="InsightsDashboardFragment__encrypted_messages">Encrypted messages</string>
<string name="InsightsDashboardFragment__cancel">Cancel</string>
<string name="InsightsDashboardFragment__send">Send</string>
Expand Down
2 changes: 2 additions & 0 deletions src/org/thoughtcrime/securesms/ApplicationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider;
import org.thoughtcrime.securesms.gcm.FcmJobService;
import org.thoughtcrime.securesms.insights.InsightsOptOut;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.JobMigrator;
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
Expand Down Expand Up @@ -239,6 +240,7 @@ private void initializeFirstEverAppLaunch() {
if (!SQLCipherOpenHelper.databaseFileExists(this)) {
Log.i(TAG, "First ever app launch!");

InsightsOptOut.userRequestedOptOut(this);
TextSecurePreferences.setAppMigrationVersion(this, ApplicationMigrations.CURRENT_VERSION);
TextSecurePreferences.setJobManagerVersion(this, JobManager.CURRENT_VERSION);
}
Expand Down
28 changes: 9 additions & 19 deletions src/org/thoughtcrime/securesms/database/MessagingDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@

import androidx.annotation.NonNull;

import com.annimon.stream.Stream;

import net.sqlcipher.database.SQLiteDatabase;

import org.thoughtcrime.securesms.database.documents.Document;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchList;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.insights.InsightsConstants;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.IdentityKey;

import java.io.IOException;
Expand Down Expand Up @@ -49,7 +47,7 @@ final int getInsecureMessagesSentForThread(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] projection = new String[]{"COUNT(*)"};
String query = THREAD_ID + " = ? AND " + getOutgoingInsecureMessageClause() + " AND " + getDateSentColumnName() + " > ?";
String[] args = new String[]{String.valueOf(threadId), String.valueOf(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7))};
String[] args = new String[]{String.valueOf(threadId), String.valueOf(System.currentTimeMillis() - InsightsConstants.PERIOD_IN_MILLIS)};

try (Cursor cursor = db.query(getTableName(), projection, query, args, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
Expand All @@ -60,28 +58,20 @@ final int getInsecureMessagesSentForThread(long threadId) {
}
}

final int getInsecureMessageCountForRecipients(List<RecipientId> recipients) {
return getMessageCountForRecipientsAndType(recipients, getOutgoingInsecureMessageClause());
final int getInsecureMessageCountForInsights() {
return getMessageCountForRecipientsAndType(getOutgoingInsecureMessageClause());
}

final int getSecureMessageCountForRecipients(List<RecipientId> recipients) {
return getMessageCountForRecipientsAndType(recipients, getOutgoingSecureMessageClause());
final int getSecureMessageCountForInsights() {
return getMessageCountForRecipientsAndType(getOutgoingSecureMessageClause());
}

private int getMessageCountForRecipientsAndType(List<RecipientId> recipients, String typeClause) {
if (recipients.size() == 0) return 0;
private int getMessageCountForRecipientsAndType(String typeClause) {

SQLiteDatabase db = databaseHelper.getReadableDatabase();
String placeholders = Util.join(Stream.of(recipients).map(r -> "?").toList(), ",");
String[] projection = new String[] {"COUNT(*)"};
String query = RECIPIENT_ID + " IN ( " + placeholders + " ) AND " + typeClause + " AND " + getDateSentColumnName() + " > ?";
String[] args = new String[recipients.size() + 1];

for (int i = 0; i < recipients.size(); i++) {
args[i] = recipients.get(i).serialize();
}

args[args.length - 1] = String.valueOf(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7));
String query = typeClause + " AND " + getDateSentColumnName() + " > ?";
String[] args = new String[]{String.valueOf(System.currentTimeMillis() - InsightsConstants.PERIOD_IN_MILLIS)};

try (Cursor cursor = db.query(getTableName(), projection, query, args, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
Expand Down
14 changes: 7 additions & 7 deletions src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import android.content.Context;
import android.database.Cursor;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

Expand All @@ -31,7 +32,6 @@
import org.thoughtcrime.securesms.recipients.RecipientId;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MmsSmsDatabase extends Database {
Expand Down Expand Up @@ -163,16 +163,16 @@ public int getInsecureSentCount(long threadId) {
return count;
}

public int getInsecureMessageCountForRecipients(List<RecipientId> recipients) {
int count = DatabaseFactory.getSmsDatabase(context).getInsecureMessageCountForRecipients(recipients);
count += DatabaseFactory.getMmsDatabase(context).getInsecureMessageCountForRecipients(recipients);
public int getInsecureMessageCountForInsights() {
int count = DatabaseFactory.getSmsDatabase(context).getInsecureMessageCountForInsights();
count += DatabaseFactory.getMmsDatabase(context).getInsecureMessageCountForInsights();

return count;
}

public int getSecureMessageCountForRecipients(List<RecipientId> recipients) {
int count = DatabaseFactory.getSmsDatabase(context).getSecureMessageCountForRecipients(recipients);
count += DatabaseFactory.getMmsDatabase(context).getSecureMessageCountForRecipients(recipients);
public int getSecureMessageCountForInsights() {
int count = DatabaseFactory.getSmsDatabase(context).getSecureMessageCountForInsights();
count += DatabaseFactory.getMmsDatabase(context).getSecureMessageCountForInsights();

return count;
}
Expand Down
35 changes: 6 additions & 29 deletions src/org/thoughtcrime/securesms/database/RecipientDatabase.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.database;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
Expand Down Expand Up @@ -37,6 +36,7 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RecipientDatabase extends Database {

Expand Down Expand Up @@ -205,8 +205,9 @@ public static InsightsBannerTier fromId(int id) {
TABLE_NAME + "." + GROUP_ID + " IS NULL AND " +
TABLE_NAME + "." + REGISTERED + " = " + RegisteredState.NOT_REGISTERED.id + " AND " +
TABLE_NAME + "." + SEEN_INVITE_REMINDER + " < " + InsightsBannerTier.TIER_TWO.id + " AND " +
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.HAS_SENT +
" ORDER BY " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.DATE + " DESC";
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.HAS_SENT + " AND " +
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.DATE + " > ?" +
" ORDER BY " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.DATE + " DESC LIMIT 50";

public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
Expand Down Expand Up @@ -618,33 +619,9 @@ public void setRegistered(@NonNull Collection<RecipientId> activeIds,
public @NonNull List<RecipientId> getUninvitedRecipientsForInsights() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
List<RecipientId> results = new LinkedList<>();
final String[] args = new String[]{String.valueOf(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31))};

try (Cursor cursor = db.rawQuery(INSIGHTS_INVITEE_LIST, null)) {
while (cursor != null && cursor.moveToNext()) {
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))));
}
}

return results;
}

public @NonNull List<RecipientId> getNotRegisteredForInsights() {
return getRecipientsForInsights(REGISTERED + " = ?", new String[]{String.valueOf(RegisteredState.NOT_REGISTERED.id)});
}

public @NonNull List<RecipientId> getRegisteredForInsights() {
final String selfId = Recipient.self().getId().serialize();
final String query = REGISTERED + " = ? AND " + ID + " != ?";
final String[] args = new String[]{String.valueOf(RegisteredState.REGISTERED.id), selfId};

return getRecipientsForInsights(query, args);
}

private @NonNull List<RecipientId> getRecipientsForInsights(@NonNull String query, @NonNull String[] args) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
List<RecipientId> results = new LinkedList<>();

try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query + " AND " + GROUP_ID + " IS NULL", args, null, null, null)) {
try (Cursor cursor = db.rawQuery(INSIGHTS_INVITEE_LIST, args)) {
while (cursor != null && cursor.moveToNext()) {
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))));
}
Expand Down
13 changes: 13 additions & 0 deletions src/org/thoughtcrime/securesms/insights/InsightsConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.thoughtcrime.securesms.insights;

import java.util.concurrent.TimeUnit;

public final class InsightsConstants {

public static final long PERIOD_IN_DAYS = 7L;
public static final long PERIOD_IN_MILLIS = TimeUnit.DAYS.toMillis(PERIOD_IN_DAYS);

private InsightsConstants() {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -182,25 +182,27 @@ private void setTitleAndDescriptionText(int insecurePercent) {
progressContainer.setVisibility(View.VISIBLE);
insecureRecipients.setVisibility(View.VISIBLE);
encryptedMessages.setText(R.string.InsightsDashboardFragment__encrypted_messages);
tagline.setText(getString(R.string.InsightsDashboardFragment__tagline, 100 - insecurePercent));
tagline.setText(getString(R.string.InsightsDashboardFragment__signal_protocol_automatically_protected, 100 - insecurePercent, InsightsConstants.PERIOD_IN_DAYS));

if (insecurePercent == 0) {
lottieAnimationView.setVisibility(View.VISIBLE);
title.setText(R.string.InsightsDashboardFragment__100_title);
description.setText(R.string.InsightsDashboardFragment__100_description);
title.setVisibility(View.GONE);
description.setVisibility(View.GONE);
} else {
lottieAnimationView.setVisibility(View.GONE);
title.setText(R.string.InsightsDashboardFragment__boost_your_signal);
description.setText(R.string.InsightsDashboardFragment__invite_your_contacts);
title.setVisibility(View.VISIBLE);
description.setVisibility(View.VISIBLE);
}
}

private void setNotEnoughDataText() {
startAConversation.setVisibility(View.VISIBLE);
progressContainer.setVisibility(View.INVISIBLE);
insecureRecipients.setVisibility(View.GONE);
encryptedMessages.setText(R.string.InsightsDashboardFragment__no_signal_yet);
tagline.setText(R.string.InsightsDashboardFragment__youre_just_getting_started);
encryptedMessages.setText(R.string.InsightsDashboardFragment__not_enough_data);
tagline.setText(getString(R.string.InsightsDashboardFragment__your_insights_percentage_is_calculated_based_on, InsightsConstants.PERIOD_IN_DAYS));
}

private void animateNotEnoughData() {
Expand Down
7 changes: 5 additions & 2 deletions src/org/thoughtcrime/securesms/insights/InsightsOptOut.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@

import org.thoughtcrime.securesms.util.TextSecurePreferences;

class InsightsOptOut {
public final class InsightsOptOut {
private static final String INSIGHTS_OPT_OUT_PREFERENCE = "insights.opt.out";

private InsightsOptOut() {
}

static boolean userHasOptedOut(@NonNull Context context) {
return TextSecurePreferences.getBooleanPreference(context, INSIGHTS_OPT_OUT_PREFERENCE, false);
}

static void userRequestedOptOut(@NonNull Context context) {
public static void userRequestedOptOut(@NonNull Context context) {
TextSecurePreferences.setBooleanPreference(context, INSIGHTS_OPT_OUT_PREFERENCE, true);
}
}
11 changes: 4 additions & 7 deletions src/org/thoughtcrime/securesms/insights/InsightsRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
Expand All @@ -39,12 +39,9 @@ public InsightsRepository(Context context) {
@Override
public void getInsightsData(@NonNull Consumer<InsightsData> insightsDataConsumer) {
SimpleTask.run(() -> {
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
List<RecipientId> unregisteredRecipients = recipientDatabase.getNotRegisteredForInsights();
List<RecipientId> registeredRecipients = recipientDatabase.getRegisteredForInsights();
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
int insecure = mmsSmsDatabase.getInsecureMessageCountForRecipients(unregisteredRecipients);
int secure = mmsSmsDatabase.getSecureMessageCountForRecipients(registeredRecipients);
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
int insecure = mmsSmsDatabase.getInsecureMessageCountForInsights();
int secure = mmsSmsDatabase.getSecureMessageCountForInsights();

if (insecure + secure == 0) {
return new InsightsData(false, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;

import java.util.List;

public final class InviteReminderRepository implements InviteReminderModel.Repository {

Expand All @@ -32,12 +29,9 @@ public void setHasSeenSecondInviteReminder(Recipient recipient) {

@Override
public int getPercentOfInsecureMessages(int insecureCount) {
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
List<RecipientId> registeredRecipients = recipientDatabase.getRegisteredForInsights();
List<RecipientId> unregisteredRecipients = recipientDatabase.getNotRegisteredForInsights();
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
int insecure = mmsSmsDatabase.getInsecureMessageCountForRecipients(unregisteredRecipients);
int secure = mmsSmsDatabase.getSecureMessageCountForRecipients(registeredRecipients);
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
int insecure = mmsSmsDatabase.getInsecureMessageCountForInsights();
int secure = mmsSmsDatabase.getSecureMessageCountForInsights();

if (insecure + secure == 0) return 0;
return Math.round(100f * (insecureCount / (float) (insecure + secure)));
Expand Down

0 comments on commit 599bb5a

Please sign in to comment.