From e07ab9b570dbd3c18afa3f4854f568beb05ca3e0 Mon Sep 17 00:00:00 2001 From: "Chris J. Karr" Date: Sun, 8 Jan 2017 11:21:30 -0600 Subject: [PATCH] Data disclosure form work --- AndroidManifest.xml | 6 +- .../generator_location_disclosure.html | 26 ++ .../ic_button_disclosure_setting.png | Bin 0 -> 1968 bytes .../ic_button_disclosure_setting.png | Bin 0 -> 1650 bytes .../ic_button_disclosure_setting.png | Bin 0 -> 2330 bytes .../ic_button_disclosure_setting.png | Bin 0 -> 3127 bytes .../ic_button_disclosure_setting.png | Bin 0 -> 3577 bytes res/layout/dialog_location_randomized.xml | 18 + res/layout/dialog_location_user.xml | 18 + .../layout_data_disclosure_detail_pdk.xml | 19 + res/layout/layout_data_disclosure_pdk.xml | 31 ++ res/layout/row_disclosure_action_pdk.xml | 19 + .../row_disclosure_location_accuracy_pdk.xml | 26 ++ .../row_generator_disclosure_generic.xml | 25 ++ res/values/generators.xml | 27 ++ res/values/strings.xml | 7 + .../activities/DataDisclosureActivity.java | 44 +++ .../DataDisclosureDetailActivity.java | 123 ++++++ .../activities/DataStreamActivity.java | 7 - .../generators/GeneratorViewHolder.java | 10 + .../generators/GeneratorsAdapter.java | 129 ++++++ .../generators/Generator.java | 15 + .../generators/Generators.java | 1 + .../generators/device/Location.java | 370 ++++++++++++++++++ 24 files changed, 913 insertions(+), 8 deletions(-) create mode 100755 assets/html/passive_data_kit/generator_location_disclosure.html create mode 100755 res/drawable-hdpi/ic_button_disclosure_setting.png create mode 100755 res/drawable-mdpi/ic_button_disclosure_setting.png create mode 100755 res/drawable-xhdpi/ic_button_disclosure_setting.png create mode 100755 res/drawable-xxhdpi/ic_button_disclosure_setting.png create mode 100755 res/drawable-xxxhdpi/ic_button_disclosure_setting.png create mode 100755 res/layout/dialog_location_randomized.xml create mode 100755 res/layout/dialog_location_user.xml create mode 100755 res/layout/layout_data_disclosure_detail_pdk.xml create mode 100755 res/layout/layout_data_disclosure_pdk.xml create mode 100755 res/layout/row_disclosure_action_pdk.xml create mode 100755 res/layout/row_disclosure_location_accuracy_pdk.xml create mode 100755 res/layout/row_generator_disclosure_generic.xml create mode 100755 src/com/audacious_software/passive_data_kit/activities/DataDisclosureActivity.java create mode 100755 src/com/audacious_software/passive_data_kit/activities/DataDisclosureDetailActivity.java create mode 100755 src/com/audacious_software/passive_data_kit/activities/generators/GeneratorViewHolder.java create mode 100755 src/com/audacious_software/passive_data_kit/activities/generators/GeneratorsAdapter.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index daf0bdd..45147a5 100755 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5,10 +5,14 @@ - + + + diff --git a/assets/html/passive_data_kit/generator_location_disclosure.html b/assets/html/passive_data_kit/generator_location_disclosure.html new file mode 100755 index 0000000..583b4d7 --- /dev/null +++ b/assets/html/passive_data_kit/generator_location_disclosure.html @@ -0,0 +1,26 @@ + + + + + + + +

+ TODO: Write disclosure for use of location data... +

+ +

+ Place completed file in assets/html/passive_data_kit/generator_location_disclosure.html in your project to override this placeholder. +

+ + \ No newline at end of file diff --git a/res/drawable-hdpi/ic_button_disclosure_setting.png b/res/drawable-hdpi/ic_button_disclosure_setting.png new file mode 100755 index 0000000000000000000000000000000000000000..9628f97acd37043be76d45a8eb3ddd6f6d6c3d4e GIT binary patch literal 1968 zcmaJ?dsI?)9LE4P6*om!X~%Bl@rcD!MPQO57nBkXp%v9;B3$97aOrYU)KyN-9=2Ax zxn6UR>|NGYL20_IHm#12v@(|K zy$njDPyrGIg@AY_kD=ql@__^alM^rCbK_7GjA`u*vvtNO0|;4l zC~U!C#0+>CwK<3l6VdQUU#4KPjM18{ugZiMjAhqaSR5wXlhUZ6Lh=8mCexU;6;ng6 zz?6w+b{nu#F!qg7NH5e%^!5ep!Zc&e5FL@Ts9 z*z8f#U!W8Uq1eMH8W`eSW%Q!cf?^gQBf&FM{KX~jS1>Y3K|v$i zyT5m~EigQpHb|22hp#pu53h7tuRr?bN@4Zm_7#u5F1gk{DZu*+a3JkXGA)f%4g^J( zffc^N;@~k!)w=p8P2}#{+RW|Sx5rEuw>~1U+iKe19l9u2y9ejYnWHW$DvDt++Lwr3 zF4vyM#zt|)*+FaZ(;#+pjbfr^AQA@NRMF}5n1qC$rx9R|IwQkIa`{Z*xhdo-{%uf& zq6a(P$h|PRD)29!+eZ9qNk4GK-+8EOzyIy4i^;v^k$0txIjV?gZ)(k&nRBNOETMSI zDmIV<%NEI$!=HkyETuj--m~~j^)bNbh+igqrP(TCebR|fkDEI~J40NAH3PguCoDr} zF!9@(j;6`2`Cd!w|L7`Tn;ot>y{@{cGPQuHF+7;DzPV}Hwq9d$z;l_bs+aXmNo8f( zXX5ESv$CXqtGs8B_mQ>+Xi^kD!wTw!@ce>?TH?CnI@QnI9%kp6NbwzeZddu8L?XpY zw{d#n+$-nX1irOwd8bLWb@?@A#3dH`-DBcPD;nnu;oGK_rd!%%mltMlb@b)shm?w$k%rPqJ1&a5v*}5~uA8KV z-39#=KGL?R}Uxi&E<>BH56OI}OoJR+(jlRqL za~C@|?W!#Nta+sVKCo+A9bv&DXY2e9-U;u^6~{uWv3cL~>VeH!$nqP8P*HNFLpt>Q z@53sZG_WVBKb;CT_X)B-@1?lk5-j7?6%5ii=fzp>eT@@t)jv}o=wsj6y9wFkXWB7u z{tD`Q1Jl<2)ESsFd$1tv!sT;{U}x$F1y7zB`{w#*xNDw;Mt$6}lgFHWR&w{Nmc*R- zoJ)7V?Ok_RQF63OGI#CB^#<61O-zc)@?q%qZ{~kO{&U0ApSM(Rp8RkiYM;YMDd3-U z?TmTociN<)-{+omos8~TvwPc-;q1NkX63yf51ufxBWlU_;vbxQt0gB?NJ%NVhTZH} zU;6dgCWm`Zui?PZpU0Q#Nzr+FB=`ZHZ&Rag-59w+ZrItf@{n!Nh-ZoO-1KC;6KU6MNg8Ngl G%l-l9RRj(I literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_button_disclosure_setting.png b/res/drawable-mdpi/ic_button_disclosure_setting.png new file mode 100755 index 0000000000000000000000000000000000000000..a252c984fe4042ede1b548642abd8ea2b6ef8ed7 GIT binary patch literal 1650 zcmaJ?c~BE~6kb9Vxom5hXi?}It;QqSBqWhU0zx)Hu%Q^zf>e$*yGVrWZa1q5;8YG# zBUoCXii(vgicn5dK~V&!SjCDk)~Sf-pw5UhX1s7Zq_xrw0``y6o!R{z^SBhDDU#Yi$}00;`Pkcd7FqrnZ>Mgy+kJU!da0S%~v z6D!dOG^7$sHLT90u$as!ojx;7FGD#Y!C;U@&JY+e8UZcFblfDjC^%!ha%S(mhB)9@ z2%Vjl&2R41cEDMe4#`ZC=xFRMFOD|638H-m?sd*1v0rn2#!A- zCL4vO$hEL~JQs6Pa8hZSltYl&Z04H-_yn~P63S#UNFahlA|4aLGiBg3V&UPY1rrP~ zX3|pzk~R=H=ww7T5SwWQhf(^b1S2^~i<`#V#54@DAS5K@3!EiQ1Zp(@A8IsCMw@6Y z_EztI5}R}xBnD|Q6S0}nGlNT6;7mozl@x~11f?U0^ocG;rxG+_N+n28sdRR21<2JP zdIRpfTr!5zXyg&NiAHce76B_b3=iL6K;<%tC_tc=h?THdA{45mfdNt#3=1VIL}GQI zSPf5LVM4#zh~e}E7JZAAOo??G!bmciVT>|t!B90t7{Rf^<%X%Xh^FKl$D&hf378TK zF=8O+c>gu-i7UoK&h4amnZu<0F`V%{#hANjWl0(Uum&UGP@SdUzCU4C;o3QudhGF6 z<8PUTO^&5YZ1tscHK;Od;cV^t8M8M<_QN9XddKboGC%ChswG*WwGC?))omT%S{uDR zx+@&dw!KW(5JM0Ax@ES5!#5i4e7}GAiR18a`B27PTT|pQ&JLTzir|Uavj?YHToOA* zdC4#@iO(+J?EBTd=5AA*J&9eF?yKYPQ@!^N$G_-i5}*k#>3a3|g6S?_bVON4gZqxp zjpO>j@@ZaPJX9=I-6PyS=*YS=oZx@IYgW?S zvigzNa|AK>Kh0*}T$jou$Mg17xGtY&4y{TVP&FPh>xHK~dSs~z&(Ch9lG_(IZFgK= zW{5AX9`xz+o7I|kQDJU!{VCTJc0NK9+z@k;8=kPe*Q@c8HX(lI@BM7DOnC{V+0r~! zQ1vi)<*&!?y_<%;dVfghmL)8vk}jM527rCp^;Z**9wAI_+%!7xtBXTz#a*!l(b&Ox zeL!XhaeL>8dx2%K!(NLl&%fUCO;K2y;EqLHNjrrHfyn8Mek#3ezN}~*MmMks_S0*UhG@9{sJcbC}_~u zi^c$0*_i`9;knDoBhLm_9&c(4)*KC&`jQ9yLv)q zp1(bivvc0)+S>fA$`d73>L-;2%5#T*L)!Liu~&Jzl-k~X{?xTRwDruD1I_K7#$gr- zoU5t1-d2Ct?eewkn}foU&huG=OGmwY9yC*uMOmHe4D&4yU*xOFb}Hun)1giCxW5dz zJGdzBeX5|Y#Uli(Z16tYcf^y|+F~W^Uij1&k0j-O)SBbinphfn>`}|YQ?H5&7ai_S zIXZCl6!pAVLiO8KE!(IrkqEzkNgi literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_button_disclosure_setting.png b/res/drawable-xhdpi/ic_button_disclosure_setting.png new file mode 100755 index 0000000000000000000000000000000000000000..c006523765298112123dc083b8b542b22dcda1ce GIT binary patch literal 2330 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 literal 0 HcmV?d00001 diff --git a/res/drawable-xxxhdpi/ic_button_disclosure_setting.png b/res/drawable-xxxhdpi/ic_button_disclosure_setting.png new file mode 100755 index 0000000000000000000000000000000000000000..b25919efb545a64c2ae4e18934ef85780c348c28 GIT binary patch literal 3577 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 B?{xqG literal 0 HcmV?d00001 diff --git a/res/layout/dialog_location_randomized.xml b/res/layout/dialog_location_randomized.xml new file mode 100755 index 0000000..58965d7 --- /dev/null +++ b/res/layout/dialog_location_randomized.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/res/layout/dialog_location_user.xml b/res/layout/dialog_location_user.xml new file mode 100755 index 0000000..17bbf31 --- /dev/null +++ b/res/layout/dialog_location_user.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/res/layout/layout_data_disclosure_detail_pdk.xml b/res/layout/layout_data_disclosure_detail_pdk.xml new file mode 100755 index 0000000..9cd2e4e --- /dev/null +++ b/res/layout/layout_data_disclosure_detail_pdk.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/res/layout/layout_data_disclosure_pdk.xml b/res/layout/layout_data_disclosure_pdk.xml new file mode 100755 index 0000000..cc763d0 --- /dev/null +++ b/res/layout/layout_data_disclosure_pdk.xml @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/res/layout/row_disclosure_action_pdk.xml b/res/layout/row_disclosure_action_pdk.xml new file mode 100755 index 0000000..a5250e3 --- /dev/null +++ b/res/layout/row_disclosure_action_pdk.xml @@ -0,0 +1,19 @@ + + + + diff --git a/res/layout/row_disclosure_location_accuracy_pdk.xml b/res/layout/row_disclosure_location_accuracy_pdk.xml new file mode 100755 index 0000000..78cd4cc --- /dev/null +++ b/res/layout/row_disclosure_location_accuracy_pdk.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/res/layout/row_generator_disclosure_generic.xml b/res/layout/row_generator_disclosure_generic.xml new file mode 100755 index 0000000..200f44e --- /dev/null +++ b/res/layout/row_generator_disclosure_generic.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/res/values/generators.xml b/res/values/generators.xml index 2fbcf3b..cd52c21 100755 --- a/res/values/generators.xml +++ b/res/values/generators.xml @@ -43,6 +43,33 @@ Device Location Coordinates: %1$.4f, %2$.4f + Location Accuracy + Tap here to update the accuracy of your data. + + Best Accuracy + Best Available Data From Location Hardware + + Locally Randomized + Location Combined With Random Noise + + User Provided + Static Location Provided By User + + Disabled + App Does Not Use Location Data + + Best Accuracy + This app will use the location hardware on this device to obtain the most accurate location readings. + + Location Disabled + This app will not use your location, but use an placeholder instead. + + Locally Randomized + Please enter the random distance (miles/kilometers)to use to obfuscate your exact location: + + User Provided + Please enter a postal code or city and province to use as your location: + Unable to find your location. Please enter your location another way and try again. Screen State diff --git a/res/values/strings.xml b/res/values/strings.xml index a784812..73b220f 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4,6 +4,7 @@ 0.0.1 Unknown Version Data Stream + Continue %d generator @@ -20,5 +21,11 @@ Diagnostics The app is set up correctly.\n\nNo further actions are needed. + + Passive Data Disclosure + Select a disclosure item for more information… + + Data Collection Description + Tap here to learn how this app uses your data. diff --git a/src/com/audacious_software/passive_data_kit/activities/DataDisclosureActivity.java b/src/com/audacious_software/passive_data_kit/activities/DataDisclosureActivity.java new file mode 100755 index 0000000..70d41f3 --- /dev/null +++ b/src/com/audacious_software/passive_data_kit/activities/DataDisclosureActivity.java @@ -0,0 +1,44 @@ +package com.audacious_software.passive_data_kit.activities; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.MenuItem; +import android.widget.FrameLayout; + +import com.audacious_software.passive_data_kit.activities.generators.GeneratorsAdapter; +import com.audacious_software.pdk.passivedatakit.R; + +public class DataDisclosureActivity extends AppCompatActivity { + private GeneratorsAdapter mAdapter = null; + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.setContentView(R.layout.layout_data_disclosure_pdk); + this.getSupportActionBar().setTitle(R.string.title_data_disclosure); + this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + FrameLayout dataView = (FrameLayout) this.findViewById(R.id.data_view); + + this.mAdapter = new GeneratorsAdapter(); + this.mAdapter.setContext(this.getApplicationContext()); + this.mAdapter.setDataView(dataView); + + RecyclerView listView = (RecyclerView) this.findViewById(R.id.list_view); + + listView.setLayoutManager(new LinearLayoutManager(this)); + + listView.setAdapter(this.mAdapter); + } + + public boolean onOptionsItemSelected(MenuItem item) + { + if (item.getItemId() == android.R.id.home) + { + this.finish(); + } + + return true; + } +} diff --git a/src/com/audacious_software/passive_data_kit/activities/DataDisclosureDetailActivity.java b/src/com/audacious_software/passive_data_kit/activities/DataDisclosureDetailActivity.java new file mode 100755 index 0000000..aaf79bb --- /dev/null +++ b/src/com/audacious_software/passive_data_kit/activities/DataDisclosureDetailActivity.java @@ -0,0 +1,123 @@ +package com.audacious_software.passive_data_kit.activities; + +import android.content.Context; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.FrameLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.audacious_software.passive_data_kit.Logger; +import com.audacious_software.passive_data_kit.generators.Generator; +import com.audacious_software.pdk.passivedatakit.R; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +public class DataDisclosureDetailActivity extends AppCompatActivity { + public static class Action { + public String title; + public String subtitle; + + public View view; + } + + public static final String GENERATOR_CLASS_NAME = "com.audacious_software.passive_data_kit.activities.DataDisclosureDetailActivity.GENERATOR_CLASS_NAME"; + + private Class mGeneratorClass = null; + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final DataDisclosureDetailActivity me = this; + + this.setContentView(R.layout.layout_data_disclosure_detail_pdk); + this.getSupportActionBar().setSubtitle(R.string.title_data_disclosure); + this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + try { + this.mGeneratorClass = (Class) Class.forName(this.getIntent().getStringExtra(DataDisclosureDetailActivity.GENERATOR_CLASS_NAME)); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + if (this.mGeneratorClass != null) { + try { + Method getGeneratorTitle = this.mGeneratorClass.getDeclaredMethod("getGeneratorTitle", Context.class); + + String title = (String) getGeneratorTitle.invoke(null, this); + this.getSupportActionBar().setTitle(title); + + Method getDisclosureActions = this.mGeneratorClass.getDeclaredMethod("getDisclosureActions", Context.class); + + final List actions = (List) getDisclosureActions.invoke(null, this); + + ListView actionsList = (ListView) this.findViewById(R.id.disclosure_actions); + ArrayAdapter adapter = new ArrayAdapter(this, R.layout.row_disclosure_action_pdk, actions) { + public View getView (int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(me).inflate(R.layout.row_disclosure_action_pdk, null); + } + + Action action = actions.get(position); + + TextView title = (TextView) convertView.findViewById(R.id.action_title); + title.setText(action.title); + + TextView description = (TextView) convertView.findViewById(R.id.action_description); + description.setText(action.subtitle); + + return convertView; + } + }; + + actionsList.setAdapter(adapter); + + actionsList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long l) { + Log.e("PDK", "TAPPED: " + position); + + Action action = actions.get(position); + + FrameLayout dataView = (FrameLayout) me.findViewById(R.id.data_view); + dataView.removeAllViews(); + + if (action.view != null) { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + + action.view.setLayoutParams(params); + + dataView.addView(action.view); + } + } + }); + + actionsList.performItemClick(null, 0, 0); + } catch (NoSuchMethodException e1) { + Logger.getInstance(this).logThrowable(e1); + } catch (InvocationTargetException e1) { + Logger.getInstance(this).logThrowable(e1); + } catch (IllegalAccessException e1) { + Logger.getInstance(this).logThrowable(e1); + } + } + } + + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + this.finish(); + } + + return true; + } + +} diff --git a/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java b/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java index 04e416c..8815505 100755 --- a/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java +++ b/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java @@ -6,15 +6,8 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import com.audacious_software.passive_data_kit.PassiveDataKit; import com.audacious_software.passive_data_kit.activities.generators.DataPointsAdapter; -import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction; import com.audacious_software.passive_data_kit.generators.Generators; import com.audacious_software.pdk.passivedatakit.R; diff --git a/src/com/audacious_software/passive_data_kit/activities/generators/GeneratorViewHolder.java b/src/com/audacious_software/passive_data_kit/activities/generators/GeneratorViewHolder.java new file mode 100755 index 0000000..5726eb2 --- /dev/null +++ b/src/com/audacious_software/passive_data_kit/activities/generators/GeneratorViewHolder.java @@ -0,0 +1,10 @@ +package com.audacious_software.passive_data_kit.activities.generators; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +public class GeneratorViewHolder extends RecyclerView.ViewHolder { + public GeneratorViewHolder(View itemView) { + super(itemView); + } +} diff --git a/src/com/audacious_software/passive_data_kit/activities/generators/GeneratorsAdapter.java b/src/com/audacious_software/passive_data_kit/activities/generators/GeneratorsAdapter.java new file mode 100755 index 0000000..adf3618 --- /dev/null +++ b/src/com/audacious_software/passive_data_kit/activities/generators/GeneratorsAdapter.java @@ -0,0 +1,129 @@ +package com.audacious_software.passive_data_kit.activities.generators; + +import android.content.Context; +import android.content.Intent; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.Toast; + +import com.audacious_software.passive_data_kit.Logger; +import com.audacious_software.passive_data_kit.activities.DataDisclosureDetailActivity; +import com.audacious_software.passive_data_kit.generators.Generator; +import com.audacious_software.passive_data_kit.generators.Generators; +import com.audacious_software.pdk.passivedatakit.R; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class GeneratorsAdapter extends RecyclerView.Adapter { + private Context mContext = null; + private FrameLayout mDataView = null; + + @Override + public GeneratorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = Generator.fetchDisclosureView(parent); + + return new GeneratorViewHolder(view); + } + + @Override + public void onBindViewHolder(final GeneratorViewHolder holder, int position) { + final GeneratorsAdapter me = this; + + List> activeGenerators = Generators.getInstance(holder.itemView.getContext()).activeGenerators(); + + this.sortGenerators(this.mContext, activeGenerators); + + Class generatorClass = activeGenerators.get(position); + + Log.e("PDK", "GENERATOR CLASS: " + generatorClass); + + try { + Method bindViewHolder = generatorClass.getDeclaredMethod("bindDisclosureViewHolder", GeneratorViewHolder.class); + bindViewHolder.invoke(null, holder); + } catch (Exception e) { +// e.printStackTrace(); + try { + generatorClass = Generator.class; + + Method bindViewHolder = generatorClass.getDeclaredMethod("bindDisclosureViewHolder", GeneratorViewHolder.class); + + bindViewHolder.invoke(null, holder); + } catch (NoSuchMethodException e1) { + Logger.getInstance(holder.itemView.getContext()).logThrowable(e1); + } catch (InvocationTargetException e1) { + Logger.getInstance(holder.itemView.getContext()).logThrowable(e1); + } catch (IllegalAccessException e1) { + Logger.getInstance(holder.itemView.getContext()).logThrowable(e1); + } + } + + final Class finalClass = generatorClass; + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + me.mDataView.removeAllViews(); + + try { + Method bindViewHolder = finalClass.getDeclaredMethod("getDisclosureDataView", GeneratorViewHolder.class); + + View dataView = (View) bindViewHolder.invoke(null, holder); + me.mDataView.addView(dataView); + } catch (NoSuchMethodException e1) { + Logger.getInstance(holder.itemView.getContext()).logThrowable(e1); + } catch (InvocationTargetException e1) { + Logger.getInstance(holder.itemView.getContext()).logThrowable(e1); + } catch (IllegalAccessException e1) { + Logger.getInstance(holder.itemView.getContext()).logThrowable(e1); + } + } + }); + + ImageView settingsButton = (ImageView) holder.itemView.findViewById(R.id.button_disclosure_item); + + settingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(holder.itemView.getContext(), DataDisclosureDetailActivity.class); + intent.putExtra(DataDisclosureDetailActivity.GENERATOR_CLASS_NAME, finalClass.getCanonicalName()); + + holder.itemView.getContext().startActivity(intent); + } + }); + + } + + @Override + public int getItemCount() { + return Generators.getInstance(null).activeGenerators().size(); + } + + private void sortGenerators(final Context context, List> generators) { + Collections.sort(generators, new Comparator>() { + @Override + public int compare(Class one, Class two) { + return one.getName().compareTo(two.getName()); + } + }); + } + + public int getItemViewType (int position) { + return 0; + } + + public void setContext(Context context) { + this.mContext = context; + } + + public void setDataView(FrameLayout dataView) { + this.mDataView = dataView; + } +} diff --git a/src/com/audacious_software/passive_data_kit/generators/Generator.java b/src/com/audacious_software/passive_data_kit/generators/Generator.java index abb0938..4adc72e 100755 --- a/src/com/audacious_software/passive_data_kit/generators/Generator.java +++ b/src/com/audacious_software/passive_data_kit/generators/Generator.java @@ -11,6 +11,7 @@ import android.widget.TextView; import com.audacious_software.passive_data_kit.activities.generators.DataPointViewHolder; +import com.audacious_software.passive_data_kit.activities.generators.GeneratorViewHolder; import com.audacious_software.pdk.passivedatakit.R; import java.text.DateFormat; @@ -82,6 +83,20 @@ public static void bindViewHolder(DataPointViewHolder holder) { generatorLabel.setText(identifier); } + public static View fetchDisclosureView(ViewGroup parent) { + return LayoutInflater.from(parent.getContext()).inflate(R.layout.row_generator_disclosure_generic, parent, false); + } + + public static void bindDisclosureViewHolder(GeneratorViewHolder holder) { + Class currentClass = new Object() { }.getClass().getEnclosingClass(); + + String identifier = currentClass.getCanonicalName(); + + TextView generatorLabel = (TextView) holder.itemView.findViewById(R.id.label_generator); + + generatorLabel.setText(identifier); + } + public static String formatTimestamp(Context context, double timestamp) { timestamp *= 1000; diff --git a/src/com/audacious_software/passive_data_kit/generators/Generators.java b/src/com/audacious_software/passive_data_kit/generators/Generators.java index 42b4cd9..ddac98b 100755 --- a/src/com/audacious_software/passive_data_kit/generators/Generators.java +++ b/src/com/audacious_software/passive_data_kit/generators/Generators.java @@ -24,6 +24,7 @@ public class Generators { private Context mContext = null; private boolean mStarted = false; + private ArrayList mGenerators = new ArrayList<>(); private HashSet mActiveGenerators = new HashSet<>(); private SharedPreferences mSharedPreferences = null; diff --git a/src/com/audacious_software/passive_data_kit/generators/device/Location.java b/src/com/audacious_software/passive_data_kit/generators/device/Location.java index f00204c..64c74b0 100755 --- a/src/com/audacious_software/passive_data_kit/generators/device/Location.java +++ b/src/com/audacious_software/passive_data_kit/generators/device/Location.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.content.ContentValues; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -12,6 +13,8 @@ import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.location.Address; +import android.location.Geocoder; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; @@ -20,18 +23,28 @@ import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.SwitchCompat; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.webkit.WebView; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import com.audacious_software.passive_data_kit.DeviceInformation; import com.audacious_software.passive_data_kit.PassiveDataKit; +import com.audacious_software.passive_data_kit.activities.DataDisclosureDetailActivity; import com.audacious_software.passive_data_kit.activities.generators.DataPointViewHolder; +import com.audacious_software.passive_data_kit.activities.generators.GeneratorViewHolder; import com.audacious_software.passive_data_kit.activities.generators.RequestPermissionActivity; import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction; import com.audacious_software.passive_data_kit.generators.Generator; @@ -53,6 +66,7 @@ import com.google.maps.android.ui.IconGenerator; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -79,6 +93,22 @@ public class Location extends Generator implements GoogleApiClient.ConnectionCal private static final String SETTING_DISPLAY_HYBRID_MAP = "com.audacious_software.passive_data_kit.generators.device.Location.SETTING_DISPLAY_HYBRID_MAP"; private static final boolean SETTING_DISPLAY_HYBRID_MAP_DEFAULT = true; + private static String ACCURACY_MODE = "com.audacious_software.passive_data_kit.generators.device.Location.ACCURACY_MODE"; + + private static int ACCURACY_BEST = 0; + private static int ACCURACY_RANDOMIZED = 1; + private static int ACCURACY_USER = 2; + private static int ACCURACY_DISABLED = 3; + + private static final String ACCURACY_MODE_RANDOMIZED_RANGE = "com.audacious_software.passive_data_kit.generators.device.Location.ACCURACY_MODE_RANDOMIZED_RANGE"; + private static final long ACCURACY_MODE_RANDOMIZED_RANGE_DEFAULT = 100; + + private static final String ACCURACY_MODE_USER_LOCATION = "com.audacious_software.passive_data_kit.generators.device.Location.ACCURACY_MODE_USER_LOCATION"; + private static final String ACCURACY_MODE_USER_LOCATION_DEFAULT = "Chicago, Illinois"; + + private static final String ACCURACY_MODE_USER_LOCATION_LATITUDE = "com.audacious_software.passive_data_kit.generators.device.Location.ACCURACY_MODE_USER_LOCATION_LATITUDE"; + private static final String ACCURACY_MODE_USER_LOCATION_LONGITUDE = "com.audacious_software.passive_data_kit.generators.device.Location.ACCURACY_MODE_USER_LOCATION_LONGITUDE"; + private static Location sInstance = null; private GoogleApiClient mGoogleApiClient = null; private android.location.Location mLastLocation = null; @@ -524,7 +554,347 @@ else if (Location.useGoogleLocationServices(parent.getContext())) } } + public static String getGeneratorTitle(Context context) { + return context.getString(R.string.generator_location); + } + + public static List getDisclosureActions(final Context context) { + List actions = new ArrayList<>(); + + DataDisclosureDetailActivity.Action disclosure = new DataDisclosureDetailActivity.Action(); + + disclosure.title = context.getString(R.string.label_data_collection_description); + disclosure.subtitle = context.getString(R.string.label_data_collection_description_more); + + WebView disclosureView = new WebView(context); + disclosureView.loadUrl("file:///android_asset/html/passive_data_kit/generator_location_disclosure.html"); + + disclosure.view = disclosureView; + + actions.add(disclosure); + + DataDisclosureDetailActivity.Action accuracy = new DataDisclosureDetailActivity.Action(); + accuracy.title = context.getString(R.string.label_data_collection_location_accuracy); + accuracy.subtitle = context.getString(R.string.label_data_collection_location_accuracy_more); + + final Integer[] options = { Location.ACCURACY_BEST, Location.ACCURACY_RANDOMIZED, Location.ACCURACY_USER, Location.ACCURACY_DISABLED }; + + final ListView listView = new ListView(context); + + final ArrayAdapter accuracyAdapter = new ArrayAdapter(context, R.layout.row_disclosure_location_accuracy_pdk, options) { + public View getView (final int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(context).inflate(R.layout.row_disclosure_location_accuracy_pdk, null); + } + + final Integer option = options[position]; + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + int selected = prefs.getInt(Location.ACCURACY_MODE, Location.ACCURACY_BEST); + + CheckBox checked = (CheckBox) convertView.findViewById(R.id.action_checked); + + checked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + + } + }); + + checked.setChecked(selected == option); + + TextView title = (TextView) convertView.findViewById(R.id.action_title); + TextView description = (TextView) convertView.findViewById(R.id.action_description); + + if (option == Location.ACCURACY_BEST) { + title.setText(R.string.label_data_collection_location_accuracy_best); + description.setText(R.string.label_data_collection_location_accuracy_best_more); + } else if (option == Location.ACCURACY_RANDOMIZED) { + title.setText(R.string.label_data_collection_location_accuracy_randomized); + description.setText(R.string.label_data_collection_location_accuracy_randomized_more); + } else if (option == Location.ACCURACY_USER) { + title.setText(R.string.label_data_collection_location_accuracy_user); + description.setText(R.string.label_data_collection_location_accuracy_user_more); + } else if (option == Location.ACCURACY_DISABLED) { + title.setText(R.string.label_data_collection_location_accuracy_disabled); + description.setText(R.string.label_data_collection_location_accuracy_disabled_more); + } + + final ArrayAdapter meAdapter = this; + + checked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(final CompoundButton compoundButton, final boolean checked) { + Log.e("PDK", "CHECK CHANGE!"); + + final CompoundButton.OnCheckedChangeListener me = this; + + if (option == Location.ACCURACY_BEST) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.title_location_accuracy_best); + builder.setMessage(R.string.message_location_accuracy_best); + + builder.setPositiveButton(R.string.action_continue, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + SharedPreferences.Editor e = prefs.edit(); + e.putInt(Location.ACCURACY_MODE, option); + e.apply(); + + meAdapter.notifyDataSetChanged(); + } + }); + + builder.create().show(); + } else if (option == Location.ACCURACY_RANDOMIZED) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.title_location_accuracy_randomized); + + View body = LayoutInflater.from(context).inflate(R.layout.dialog_location_randomized, null); + builder.setView(body); + + final EditText rangeField = (EditText) body.findViewById(R.id.random_range); + + long existingRange = prefs.getLong(Location.ACCURACY_MODE_RANDOMIZED_RANGE, Location.ACCURACY_MODE_RANDOMIZED_RANGE_DEFAULT); + + rangeField.setText("" + existingRange); + + builder.setPositiveButton(R.string.action_continue, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + SharedPreferences.Editor e = prefs.edit(); + + long randomRange = Long.parseLong(rangeField.getText().toString()); + + e.putLong(Location.ACCURACY_MODE_RANDOMIZED_RANGE, randomRange); + + e.putInt(Location.ACCURACY_MODE, option); + e.apply(); + + meAdapter.notifyDataSetChanged(); + } + }); + + builder.create().show(); + } else if (option == Location.ACCURACY_USER) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.title_location_accuracy_user); + + View body = LayoutInflater.from(context).inflate(R.layout.dialog_location_user, null); + builder.setView(body); + + final EditText locationField = (EditText) body.findViewById(R.id.user_location); + + String existingLocation = prefs.getString(Location.ACCURACY_MODE_USER_LOCATION, Location.ACCURACY_MODE_USER_LOCATION_DEFAULT); + + locationField.setText(existingLocation); + + builder.setPositiveButton(R.string.action_continue, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + SharedPreferences.Editor e = prefs.edit(); + + String location = locationField.getText().toString(); + + e.putString(Location.ACCURACY_MODE_USER_LOCATION, location); + + try { + List
results = (new Geocoder(context)).getFromLocationName(location, 1); + + if (results.size() > 0) { + Address match = results.get(0); + + e.putFloat(Location.ACCURACY_MODE_USER_LOCATION_LATITUDE, (float) match.getLatitude()); + e.putFloat(Location.ACCURACY_MODE_USER_LOCATION_LONGITUDE, (float) match.getLongitude()); + } else { + Toast.makeText(context, R.string.toast_location_lookup_failed, Toast.LENGTH_LONG).show(); + + me.onCheckedChanged(compoundButton, checked); + } + } catch (IOException e1) { + e1.printStackTrace(); + } + + e.putInt(Location.ACCURACY_MODE, option); + e.apply(); + + meAdapter.notifyDataSetChanged(); + } + }); + + builder.create().show(); + } else if (option == Location.ACCURACY_DISABLED) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.title_location_accuracy_disabled); + builder.setMessage(R.string.message_location_accuracy_disabled); + + builder.setPositiveButton(R.string.action_continue, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + SharedPreferences.Editor e = prefs.edit(); + e.putInt(Location.ACCURACY_MODE, option); + e.apply(); + + meAdapter.notifyDataSetChanged(); + } + }); + + builder.create().show(); + } + + } + }); + + return convertView; + } + }; + + listView.setAdapter(accuracyAdapter); + + accuracy.view = listView; + + actions.add(accuracy); + + return actions; + } + + public static View getDisclosureDataView(final GeneratorViewHolder holder) { + final Context context = holder.itemView.getContext(); + + if (Location.useKindleLocationServices()) + { + // TODO + throw new RuntimeException("Throw rocks at developer to implement Kindle support."); + } + else if (Location.useGoogleLocationServices(holder.itemView.getContext())) + { + final MapView mapView = new MapView(context); + + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mapView.setLayoutParams(params); + + mapView.onCreate(null); + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + + final boolean useHybrid = prefs.getBoolean(Location.SETTING_DISPLAY_HYBRID_MAP, Location.SETTING_DISPLAY_HYBRID_MAP_DEFAULT); + + IconGenerator iconGen = new IconGenerator(context); + + Drawable shapeDrawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_location_heatmap_marker, null); + iconGen.setBackground(shapeDrawable); + + View view = new View(context); + view.setLayoutParams(new ViewGroup.LayoutParams(8, 8)); + iconGen.setContentView(view); + + final Bitmap bitmap = iconGen.makeIcon(); + + mapView.getMapAsync(new OnMapReadyCallback() { + public void onMapReady(GoogleMap googleMap) { + if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED || + ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + googleMap.setMyLocationEnabled(true); + } + + if (useHybrid) { + googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); + } else { + googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); + } + + googleMap.getUiSettings().setZoomControlsEnabled(true); + googleMap.getUiSettings().setMyLocationButtonEnabled(false); + googleMap.getUiSettings().setMapToolbarEnabled(false); + googleMap.getUiSettings().setAllGesturesEnabled(false); + + Location me = Location.getInstance(context); + + double lastLatitude = 0.0; + double lastLongitude = 0.0; + long timestamp = 0; + + final List locations = new ArrayList<>(); + + String where = Location.HISTORY_OBSERVED + " > ?"; + String[] args = { "" + (System.currentTimeMillis() - (1000 * 60 * 60 * 24)) }; + + Cursor c = me.mDatabase.query(Location.TABLE_HISTORY, null, where, args, null, null, Location.HISTORY_OBSERVED); + + while (c.moveToNext()) { + lastLatitude = c.getDouble(c.getColumnIndex(Location.HISTORY_LATITUDE)); + lastLongitude = c.getDouble(c.getColumnIndex(Location.HISTORY_LONGITUDE)); + + LatLng location = new LatLng(lastLatitude, lastLongitude); + + locations.add(location); + } + + c.close(); + + LatLngBounds.Builder builder = new LatLngBounds.Builder(); + + for (LatLng latlng : locations) { + builder.include(latlng); + } + + final DisplayMetrics metrics = new DisplayMetrics(); + ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics); + + if (locations.size() > 0) { + googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), (int) (16 * metrics.density))); + } + + for (LatLng latLng : locations) { + googleMap.addMarker(new MarkerOptions() + .position(latLng) + .icon(BitmapDescriptorFactory.fromBitmap(bitmap))); + } + + mapView.onResume(); + } + }); + + return mapView; + } + else + { + // TODO + throw new RuntimeException("Throw rocks at developer to implement generic location support."); + } + } + + public static void bindDisclosureViewHolder(final GeneratorViewHolder holder) { + Class currentClass = new Object() { }.getClass().getEnclosingClass(); + + String identifier = currentClass.getCanonicalName(); + + TextView generatorLabel = (TextView) holder.itemView.findViewById(R.id.label_generator); + + generatorLabel.setText(Location.getGeneratorTitle(holder.itemView.getContext())); + } + public android.location.Location getLastKnownLocation() { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.mContext); + int selected = prefs.getInt(Location.ACCURACY_MODE, Location.ACCURACY_BEST); + + if (selected == Location.ACCURACY_USER) { + double latitude = prefs.getFloat(Location.ACCURACY_MODE_USER_LOCATION_LATITUDE, 0); + double longitude = prefs.getFloat(Location.ACCURACY_MODE_USER_LOCATION_LONGITUDE, 0); + + android.location.Location location = new android.location.Location(""); + location.setLatitude(latitude); + location.setLongitude(longitude); + + return location; + } else if (selected == Location.ACCURACY_DISABLED) { + android.location.Location location = new android.location.Location(""); + location.setLatitude(41.8781); + location.setLongitude(-87.6298); + + return location; + } + if (this.mLastLocation != null) { return this.mLastLocation; }