Update insights copy and queries.

master
Alex Hart 2019-11-15 16:33:54 -04:00 committed by GitHub
parent 739fe584c6
commit 599bb5ab0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 62 additions and 86 deletions

View File

@ -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" />

View File

@ -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>

View File

@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
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;
@ -239,6 +240,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
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);
}

View File

@ -7,18 +7,16 @@ import android.text.TextUtils;
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;
@ -49,7 +47,7 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
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()) {
@ -60,28 +58,20 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
}
}
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()) {

View File

@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.database;
import android.content.Context;
import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -31,7 +32,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MmsSmsDatabase extends Database {
@ -163,16 +163,16 @@ public class MmsSmsDatabase extends Database {
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;
}

View File

@ -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;
@ -37,6 +36,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class RecipientDatabase extends Database {
@ -205,8 +205,9 @@ public class RecipientDatabase extends Database {
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);
@ -618,33 +619,9 @@ public class RecipientDatabase extends Database {
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))));
}

View File

@ -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() {
}
}

View File

@ -182,16 +182,18 @@ public final class InsightsDashboardDialogFragment extends DialogFragment {
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);
}
}
@ -199,8 +201,8 @@ public final class InsightsDashboardDialogFragment extends DialogFragment {
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() {

View File

@ -6,14 +6,17 @@ import androidx.annotation.NonNull;
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);
}
}

View File

@ -16,11 +16,11 @@ import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
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;
@ -39,12 +39,9 @@ public class InsightsRepository implements InsightsDashboardViewModel.Repository
@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);

View File

@ -6,9 +6,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
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 {
@ -32,12 +29,9 @@ public final class InviteReminderRepository implements InviteReminderModel.Repos
@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)));