Skip to content
This repository has been archived by the owner on Mar 27, 2020. It is now read-only.

PanicKit integration #157

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
compile 'com.google.code.gson:gson:2.3'
compile 'com.android.support:support-v4:23.1.+'
compile 'com.android.support:preference-v7:23.1.0'
compile 'info.guardianproject.panic:panic:0.5'
testCompile "org.robolectric:robolectric:3.0"
testCompile "org.robolectric:shadows-support-v4:3.0"
testCompile 'junit:junit:4.12'
Expand All @@ -47,6 +48,7 @@ dependencyVerification {
'com.android.support:appcompat-v7:b5783b390d1440769c9b8a7b42290523a4ff058ef2d3fb90c983973934ca115b',
'com.android.support:recyclerview-v7:464ec6e5004400a4fe0310f35343da9e5a2912386a3606db3585f7cf987c444a',
'com.crashlytics.sdk.android:answers:5af101ef6b58a26dd32cfc13f53c63c33fb2fdcdf6990241eca22e7a8c842847',
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
'io.fabric.sdk.android:fabric:15465f60ee6a2bb53dcf84e8dd939ce92dffbffc73bfdd3432b63fa6ee2f7bae',
'com.crashlytics.sdk.android:crashlytics-core:2f35df62420723d4a8e58f58a376fb640d11e1660656a9aa2959bb041b5b1d15',
'com.crashlytics.sdk.android:beta:6d7dce749fd70fa20adcf089aaed5d52f9e8e2a08f6666336e90a7555cee9718',
Expand Down
14 changes: 13 additions & 1 deletion app/src/main/assets/mobile_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,14 @@
],
"content": "<p>Security Tips</p><ul><li>Think about who can practically assist you - there is no point someone knowing you are in trouble if they are not in a position to help you</li><li>Make a plan with your chosen contacts so that they are prepared to act fast in an emergency”. </li><li>Be aware of the risks - how might your chosen contact be put at risk? </li></ul>"
},
{
"id": "settings-panic-responders",
"lang": "en",
"type": "interactive",
"title": "Panic Responders",
"introduction": "When you trigger Panic Button, your chosen apps react. Tap EDIT to see and change that app's behaviors.",
"component": "panic-responders"
},
{
"id": "settings-code",
"lang": "en",
Expand Down Expand Up @@ -506,6 +514,10 @@
"title": "Pin Settings",
"link": "settings-code"
},
{
"title": "Panic Responders",
"link": "settings-panic-responders"
},
{
"title": "Advanced Settings",
"link": "settings-advanced"
Expand Down Expand Up @@ -896,4 +908,4 @@
}
]
}
}
}
4 changes: 4 additions & 0 deletions app/src/main/java/org/iilab/pb/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.iilab.pb.fragment.AdvancedSettingsSubScreenFragment;
import org.iilab.pb.fragment.LanguageSettingsFragment;
import org.iilab.pb.fragment.MainSetupAlertFragment;
import org.iilab.pb.fragment.PanicRespondersFragment;
import org.iilab.pb.fragment.SetupCodeFragment;
import org.iilab.pb.fragment.SetupContactsFragment;
import org.iilab.pb.fragment.SetupMessageFragment;
Expand All @@ -36,6 +37,7 @@
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_CONTACTS;
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_LANGUAGE;
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_MESSAGE;
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_PANIC_RESPONDERS;
import static org.iilab.pb.common.AppConstants.PAGE_FROM_NOT_IMPLEMENTED;
import static org.iilab.pb.common.AppConstants.PAGE_HOME_NOT_CONFIGURED;
import static org.iilab.pb.common.AppConstants.PAGE_HOME_READY;
Expand Down Expand Up @@ -141,6 +143,8 @@ public void onCreate(Bundle savedInstanceState) {
} else {
if (currentPage.getComponent().equals(PAGE_COMPONENT_CONTACTS))
fragment = new SetupContactsFragment().newInstance(pageId, FROM_MAIN_ACTIVITY);
else if (currentPage.getComponent().equals(PAGE_COMPONENT_PANIC_RESPONDERS))
fragment = new PanicRespondersFragment().newInstance(pageId, FROM_MAIN_ACTIVITY);
else if (currentPage.getComponent().equals(PAGE_COMPONENT_MESSAGE))
fragment = new SetupMessageFragment().newInstance(pageId, FROM_MAIN_ACTIVITY);
else if (currentPage.getComponent().equals(PAGE_COMPONENT_CODE))
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/org/iilab/pb/WizardActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.iilab.pb.common.MyTagHandler;
import org.iilab.pb.data.PBDatabase;
import org.iilab.pb.fragment.LanguageSettingsFragment;
import org.iilab.pb.fragment.PanicRespondersFragment;
import org.iilab.pb.fragment.SetupCodeFragment;
import org.iilab.pb.fragment.SetupContactsFragment;
import org.iilab.pb.fragment.SetupMessageFragment;
Expand All @@ -45,6 +46,7 @@
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_DISGUISE_TEST_UNLOCK;
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_LANGUAGE;
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_MESSAGE;
import static org.iilab.pb.common.AppConstants.PAGE_COMPONENT_PANIC_RESPONDERS;
import static org.iilab.pb.common.AppConstants.PAGE_FROM_NOT_IMPLEMENTED;
import static org.iilab.pb.common.AppConstants.PAGE_HOME_NOT_CONFIGURED;
import static org.iilab.pb.common.AppConstants.PAGE_HOME_NOT_CONFIGURED_ALARM;
Expand Down Expand Up @@ -147,6 +149,8 @@ public void onCreate(Bundle savedInstanceState) {
} else { // type = interactive
if (currentPage.getComponent().equals(PAGE_COMPONENT_CONTACTS))
fragment = new SetupContactsFragment().newInstance(pageId, FROM_WIZARD_ACTIVITY);
else if (currentPage.getComponent().equals(PAGE_COMPONENT_PANIC_RESPONDERS))
fragment = new PanicRespondersFragment().newInstance(pageId, FROM_WIZARD_ACTIVITY);
else if (currentPage.getComponent().equals(PAGE_COMPONENT_MESSAGE))
fragment = new SetupMessageFragment().newInstance(pageId, FROM_WIZARD_ACTIVITY);
else if (currentPage.getComponent().equals(PAGE_COMPONENT_CODE))
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/org/iilab/pb/alert/PanicAlert.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import info.guardianproject.panic.PanicTrigger;

import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static org.iilab.pb.common.AppConstants.GPS_MIN_DISTANCE;
Expand Down Expand Up @@ -75,6 +77,8 @@ public void run() {

private void activateAlert() {
setAlertActive(context, true);
// send panic triggers to responder apps that support it
PanicTrigger.sendTrigger(context);
sendFirstAlert();
registerLocationUpdate();
scheduleFutureAlert();
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/org/iilab/pb/common/AppConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public class AppConstants {
public static final String PAGE_COMPONENT_CODE = "code";
public static final String PAGE_COMPONENT_ALERT = "alert";
public static final String PAGE_COMPONENT_LANGUAGE = "language";
public static final String PAGE_COMPONENT_PANIC_RESPONDERS = "panic-responders";
public static final String PAGE_COMPONENT_ADVANCED_SETTINGS = "advanced";
public static final String PAGE_COMPONENT_ALARM_TEST_HARDWARE = "alarm-test-hardware";
public static final String PAGE_COMPONENT_ALARM_TEST_DISGUISE = "alarm-test-disguise";
Expand Down
262 changes: 262 additions & 0 deletions app/src/main/java/org/iilab/pb/fragment/PanicRespondersFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
package org.iilab.pb.fragment;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;

import org.iilab.pb.R;
import org.iilab.pb.adapter.PageItemAdapter;
import org.iilab.pb.common.ApplicationSettings;
import org.iilab.pb.data.PBDatabase;
import org.iilab.pb.model.Page;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import info.guardianproject.panic.Panic;
import info.guardianproject.panic.PanicTrigger;

public class PanicRespondersFragment extends Fragment {
public static final String TAG = "PanicRespondersFragment";

private static final String PAGE_ID = "page_id";
private static final String PARENT_ACTIVITY = "parent_activity";
private Activity activity;
DisplayMetrics metrics;
TextView tvTitle, tvIntro;
Page currentPage;
PageItemAdapter pageItemAdapter;

private static final int CONNECT_RESULT = 0x01;

private String responders[];
private Set<String> enabledResponders;
private Set<String> respondersThatCanConnect;
private ArrayList<CharSequence> appLabelList;
private ArrayList<Drawable> iconList;

private String requestPackageName;

public static PanicRespondersFragment newInstance(String pageId, int parentActivity) {
PanicRespondersFragment f = new PanicRespondersFragment();
Bundle args = new Bundle();
args.putString(PAGE_ID, pageId);
args.putInt(PARENT_ACTIVITY, parentActivity);
f.setArguments(args);
return (f);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_type_interactive_panic_responders, container, false);

tvTitle = (TextView) view.findViewById(R.id.fragment_title);
tvIntro = (TextView) view.findViewById(R.id.fragment_intro);

return view;
}

@Override
public void onResume() {
super.onResume();

enabledResponders = PanicTrigger.getEnabledResponders(activity);
respondersThatCanConnect = PanicTrigger.getRespondersThatCanConnect(activity);

// sort enabled first, then disabled
LinkedHashSet<String> a = new LinkedHashSet<String>(enabledResponders);
LinkedHashSet<String> b = new LinkedHashSet<String>(PanicTrigger.getAllResponders(activity));
b.removeAll(enabledResponders);
a.addAll(b);
responders = a.toArray(new String[a.size()]);

PackageManager pm = getActivity().getPackageManager();
appLabelList = new ArrayList<CharSequence>(responders.length);
iconList = new ArrayList<Drawable>(responders.length);
for (String packageName : responders) {
try {
appLabelList.add(pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)));
iconList.add(pm.getApplicationIcon(packageName));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}

RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recycler_view);
recyclerView.addItemDecoration(new SimpleDividerItemDecoration(activity));
recyclerView.setHasFixedSize(true); // does not change, except in onResume()
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
recyclerView.setAdapter(new RecyclerView.Adapter<AppRowHolder>() {
@Override
public AppRowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.responder_row, parent, false);
return new AppRowHolder(view);
}

@Override
public void onBindViewHolder(AppRowHolder holder, int position) {
String packageName = responders[position];
boolean canConnect = respondersThatCanConnect.contains(packageName);
holder.setupForApp(
packageName,
iconList.get(position),
appLabelList.get(position),
canConnect);
}

@Override
public int getItemCount() {
return appLabelList.size();
}
});
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);

activity = getActivity();
if (activity != null) {
metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
String pageId = getArguments().getString(PAGE_ID);
String selectedLang = ApplicationSettings.getSelectedLanguage(activity);

PBDatabase dbInstance = new PBDatabase(activity);
dbInstance.open();
currentPage = dbInstance.retrievePage(pageId, selectedLang);
dbInstance.close();

tvTitle.setText(currentPage.getTitle());

if (currentPage.getIntroduction() == null) {
tvIntro.setVisibility(View.GONE);
} else {
tvIntro.setText(currentPage.getIntroduction());
}

pageItemAdapter = new PageItemAdapter(activity, null);
pageItemAdapter.setData(currentPage.getItems());
}
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
List<Fragment> fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.onActivityResult(requestCode, resultCode, intent);
}
}
}

class AppRowHolder extends RecyclerView.ViewHolder {

private final View.OnClickListener onClickListener;
private final Switch onSwitch;
private final TextView editableLabel;
private final ImageView iconView;
private final TextView appLabelView;
private String rowPackageName;

AppRowHolder(final View row) {
super(row);

iconView = (ImageView) row.findViewById(R.id.iconView);
appLabelView = (TextView) row.findViewById(R.id.appLabel);
editableLabel = (TextView) row.findViewById(R.id.editableLabel);
onSwitch = (Switch) row.findViewById(R.id.on_switch);
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
requestPackageName = rowPackageName;
Intent intent = new Intent(Panic.ACTION_CONNECT);
intent.setPackage(requestPackageName);
startActivityForResult(intent, CONNECT_RESULT);
}
};

onSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean enabled) {
setEnabled(enabled);
if (enabled) {
PanicTrigger.enableResponder(activity, rowPackageName);
} else {
PanicTrigger.disableResponder(activity, rowPackageName);
}
}
});
}

void setEnabled(boolean enabled) {
if (enabled) {
editableLabel.setVisibility(View.VISIBLE);
appLabelView.setEnabled(true);
iconView.setEnabled(true);
iconView.setColorFilter(null);
} else {
editableLabel.setVisibility(View.GONE);
appLabelView.setEnabled(false);
iconView.setEnabled(false);
// grey out app icon when disabled
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
iconView.setColorFilter(filter);
}
}

void setupForApp(String packageName, Drawable icon, CharSequence appLabel, boolean editable) {
this.rowPackageName = packageName;
iconView.setImageDrawable(icon);
appLabelView.setText(appLabel);
if (editable) {
iconView.setOnClickListener(onClickListener);
appLabelView.setOnClickListener(onClickListener);
editableLabel.setOnClickListener(onClickListener);
editableLabel.setText(R.string.edit);
editableLabel.setTypeface(null, Typeface.BOLD);
if (Build.VERSION.SDK_INT >= 14)
editableLabel.setAllCaps(true);
} else {
iconView.setOnClickListener(null);
appLabelView.setOnClickListener(null);
editableLabel.setOnClickListener(null);
editableLabel.setText(R.string.app_hides);
editableLabel.setTypeface(null, Typeface.NORMAL);
if (Build.VERSION.SDK_INT >= 14)
editableLabel.setAllCaps(false);
}
boolean enabled = enabledResponders.contains(packageName);
if (Build.VERSION.SDK_INT >= 14)
onSwitch.setChecked(enabled);
setEnabled(enabled);
}
}

}
Loading