├── .gitignore
├── AndroidDemoApp
├── App
│ ├── build.gradle
│ ├── proguard-rules.txt
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── android
│ │ │ └── test
│ │ │ ├── AndroidDemoApplication.java
│ │ │ ├── activity
│ │ │ ├── AbstractActionBarActivity.java
│ │ │ ├── DetailActivity.java
│ │ │ ├── ResultListActivity.java
│ │ │ └── SideBarActivity.java
│ │ │ ├── adapter
│ │ │ └── VenueRecyclerAdapter.java
│ │ │ ├── client
│ │ │ ├── FoursquareClient.java
│ │ │ └── IFoursquareClient.java
│ │ │ ├── dialog
│ │ │ ├── DialogFragmentHelper.java
│ │ │ └── ProgressDialogFragment.java
│ │ │ ├── domain
│ │ │ ├── Contact.java
│ │ │ ├── Location.java
│ │ │ └── Venue.java
│ │ │ ├── dto
│ │ │ ├── ErrorType.java
│ │ │ ├── FoursquareApiErrorDto.java
│ │ │ ├── FoursquareDto.java
│ │ │ ├── Meta.java
│ │ │ ├── Response.java
│ │ │ └── VenueDto.java
│ │ │ ├── fragment
│ │ │ ├── AbstractFragment.java
│ │ │ ├── DetailFragment.java
│ │ │ ├── MainFragment.java
│ │ │ └── ResultListFragment.java
│ │ │ ├── location
│ │ │ └── GPSTracker.java
│ │ │ ├── module
│ │ │ └── AndroidDemoModule.java
│ │ │ ├── otto
│ │ │ ├── OttoBus.java
│ │ │ ├── VenueResultEvent.java
│ │ │ └── VenueSearchEvent.java
│ │ │ ├── qachee
│ │ │ └── QacheeData.java
│ │ │ ├── session
│ │ │ └── SessionManager.java
│ │ │ ├── task
│ │ │ ├── FoursquareAsyncTask.java
│ │ │ ├── SafeAsyncTask.java
│ │ │ ├── VenueBackgroundTask.java
│ │ │ └── event
│ │ │ │ ├── OnApiErrorEvent.java
│ │ │ │ ├── OnFinallyEvent.java
│ │ │ │ └── OnPreExecuteEvent.java
│ │ │ ├── utils
│ │ │ └── DataHelper.java
│ │ │ └── view
│ │ │ ├── ObservableScrollView.java
│ │ │ ├── SideBarCallback.java
│ │ │ └── VenueItemView.java
│ │ └── res
│ │ ├── anim
│ │ ├── bottom_in.xml
│ │ ├── bottom_out.xml
│ │ ├── top_in.xml
│ │ └── top_out.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_action_content_save.png
│ │ ├── ic_action_navigation_menu.png
│ │ ├── ic_action_search.png
│ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ ├── ic_action_content_save.png
│ │ ├── ic_action_navigation_menu.png
│ │ ├── ic_action_search.png
│ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_action_content_save.png
│ │ ├── ic_action_navigation_menu.png
│ │ ├── ic_action_search.png
│ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ ├── drawer_shadow.9.png
│ │ ├── ic_ab_drawer.png
│ │ ├── ic_action_content_save.png
│ │ ├── ic_action_navigation_menu.png
│ │ ├── ic_action_search.png
│ │ └── ic_launcher.png
│ │ ├── drawable-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── drawable
│ │ ├── card_view_background.xml
│ │ └── foreground_selector.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_main_overlay.xml
│ │ ├── activity_side_bar.xml
│ │ ├── fragment_detail.xml
│ │ ├── fragment_main.xml
│ │ ├── fragment_result_list.xml
│ │ ├── toolbar.xml
│ │ └── venue_item.xml
│ │ ├── menu
│ │ └── search_menu.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── README.md
├── android_demo_keystore.jks
├── signing.properties
└── web_hi_res_512.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 | target/
15 | tmp/
16 |
17 | # Local configuration file (sdk path, etc)
18 | local.properties
19 | lint.xml
20 |
21 |
22 | # Eclipse project files
23 | .classpath
24 | .project
25 | .metadata/
26 | .settings/
27 |
28 | # Android Studio project files
29 | .idea/
30 | modules.xml
31 | workspace.xml
32 | *.iml
33 | out/
34 | .gradle
35 | build/
36 |
37 | # Mac OS file
38 | .DS_Store
39 |
40 | # Windows File
41 | .thumb
42 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | // Load custom properties file signing.properties
4 | Properties props = new Properties()
5 | props.load(new FileInputStream(file(project.property('signing.properties'))))
6 |
7 | repositories {
8 | mavenCentral()
9 | }
10 |
11 | android {
12 | lintOptions {
13 | abortOnError false
14 | }
15 |
16 | compileSdkVersion 22
17 | buildToolsVersion "22.0.1"
18 |
19 | defaultConfig {
20 | minSdkVersion 14
21 | targetSdkVersion 22
22 | versionCode Integer.parseInt(project.VERSION_CODE)
23 | versionName project.VERSION_NAME
24 | }
25 |
26 | signingConfigs {
27 | release {
28 | // If you want to use another file like signing.properties...
29 | storeFile file(props['STORE_FILE'])
30 | storePassword props['STORE_PASSWORD']
31 | keyAlias props['KEY_ALIAS']
32 | keyPassword props['KEY_PASSWORD']
33 |
34 | // If you want to use the default gradle.properties use directly...
35 | // storeFile file(project.STORE_FILE)
36 | // storePassword project.STORE_PASSWORD
37 | // keyAlias project.KEY_ALIAS
38 | // keyPassword project.KEY_PASSWORD
39 | }
40 | }
41 |
42 | buildTypes {
43 | release {
44 | zipAlignEnabled true
45 | debuggable false
46 | signingConfig signingConfigs.release
47 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt'
48 | minifyEnabled true
49 | shrinkResources true
50 | }
51 |
52 | // Uncomment to see the results of using Proguard. NOTE: proguard is not needed while develop the app.
53 | // debug {
54 | // proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt'
55 | // minifyEnabled true
56 | // shrinkResources true
57 | // }
58 | }
59 |
60 | }
61 |
62 | dependencies {
63 | compile 'com.google.inject:guice:4.0-beta5:no_aop'
64 |
65 | compile 'com.melnykov:floatingactionbutton:1.0.5'
66 | compile 'com.android.support:appcompat-v7:22.1.+'
67 | compile 'com.android.support:recyclerview-v7:22.1.+'
68 |
69 | compile 'com.squareup.picasso:picasso:2.5.2'
70 | compile 'com.squareup.retrofit:retrofit:1.9.0'
71 | compile 'com.squareup.okhttp:okhttp:2.2.0'
72 | compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'
73 | compile 'com.squareup.okio:okio:1.1.0'
74 |
75 | compile 'com.google.code.gson:gson:2.3'
76 | compile 'com.squareup:otto:1.3.5'
77 |
78 | compile 'com.github.nicolasjafelle:qachee:1.2'
79 | }
80 |
81 |
82 | android.applicationVariants.all { variant ->
83 |
84 | variant.outputs.each { output ->
85 | def apk = output.outputFile
86 |
87 | def newName
88 | if (variant.buildType.debuggable ) {
89 | newName = 'Android Demo v' + project.VERSION_NAME + '_DEBUG' +'.apk';
90 | } else {
91 | newName = 'Android Demo v' + project.VERSION_NAME + '_RELEASE' + '.apk';
92 | }
93 |
94 | //noinspection GroovyAssignabilityCheck
95 | output.outputFile = new File(apk.parentFile, newName)
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/proguard-rules.txt:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/nicolas/android-studio/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the ProGuard
5 | # include property in project.properties.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 | # This is a configuration file for ProGuard.
19 | # http://proguard.sourceforge.net/index.html#manual/usage.html
20 |
21 | # Optimizations: If you don't want to optimize, use the
22 | # proguard-android.txt configuration file instead of this one, which
23 | # turns off the optimization flags. Adding optimization introduces
24 | # certain risks, since for example not all optimizations performed by
25 | # ProGuard works on all versions of Dalvik. The following flags turn
26 | # off various optimizations known to have issues, but the list may not
27 | # be complete or up to date. (The "arithmetic" optimization can be
28 | # used if you are only targeting Android 2.0 or later.) Make sure you
29 | # test thoroughly if you go this route.
30 | # an example on how to keep an entire package
31 | # -keep class com.google.zxing.**
32 | -ignorewarnings
33 | -renamesourcefileattribute SourceFile
34 | -keepattributes SourceFile,LineNumberTable,*Annotation*,Signature
35 |
36 |
37 | -keep class retrofit.** { *; }
38 | -keep class okhttp.** { *; }
39 | -keep class com.google.gson.** { *; }
40 | -keep class com.squareup.picasso.** { *; }
41 | -keep class android.support.v7.widget.** { *; }
42 | -keep class android.support.v4.** { *; }
43 | -keep class com.melnykov.fab.** { *; }
44 | -keep class javax.inject.** { *; }
45 | -keep class com.android.test.** { *; }
46 | -keep class com.google.inject.** { *; }
47 | -keep class javax.annotation.** { *; }
48 | -keep class * extends com.google.inject.AnnotationDatabase
49 |
50 | -keep interface retrofit.** { *; }
51 | -keep interface okhttp.** { *; }
52 | -keep interface com.google.gson.** { *; }
53 | -keep interface com.squareup.picasso.** { *; }
54 | -keep interface android.support.v7.widget.** { *; }
55 | -keep interface android.support.v4.** { *; }
56 | -keep interface com.melnykov.fab.** { *; }
57 | -keep interface javax.inject.** { *; }
58 | -keep interface com.android.test.** { *; }
59 | -keep interface com.google.inject.** { *; }
60 | -keep interface javax.annotation.** { *; }
61 |
62 | -keepclassmembers class ** {
63 | @com.squareup.otto.Subscribe public *;
64 | @com.squareup.otto.Produce public *;
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/AndroidDemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.android.test;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.android.test.module.AndroidDemoModule;
7 | import com.google.inject.Guice;
8 | import com.google.inject.Injector;
9 | import com.qachee.ExpirationTime;
10 | import com.qachee.QacheeManager;
11 |
12 | /**
13 | * Created by nicolas on 11/22/14.
14 | */
15 | public class AndroidDemoApplication extends Application {
16 |
17 | private static AndroidDemoApplication instance;
18 | private static final Injector INJECTOR = Guice.createInjector(new AndroidDemoModule());
19 |
20 | @Override
21 | public void onCreate() {
22 | super.onCreate();
23 | instance = this;
24 |
25 | QacheeManager.getInstance().setExpirationTime(ExpirationTime.THIRTY_SECONDS);
26 | }
27 |
28 | public static Context getAppContext() {
29 | return instance;
30 | }
31 |
32 | public static void injectMembers(final Object object) {
33 | INJECTOR.injectMembers(object);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/activity/AbstractActionBarActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.test.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentManager;
6 | import android.support.v4.app.FragmentTransaction;
7 | import android.support.v7.app.ActionBarActivity;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.View;
10 | import android.widget.FrameLayout;
11 |
12 |
13 | public abstract class AbstractActionBarActivity extends AppCompatActivity {
14 |
15 | private FrameLayout mainLayout;
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | // if (savedInstanceState == null) {
21 | setInitialFragment();
22 | // }
23 | }
24 |
25 | /**
26 | * This method defines which is the initial Fragment. Classes that extends
27 | * this Class should override it and tells the Parent Class which is the
28 | * initial fragment to load.
29 | */
30 | protected abstract void setInitialFragment();
31 |
32 |
33 | /**
34 | * This method loads the initial fragment, it should be called inside
35 | * setInitialFragment().
36 | *
37 | * @param layoutResId - the activity layout
38 | * @param viewId - the Main view id.
39 | * @param fragment - the initial Fragment
40 | */
41 | protected void setInitialFragment(int layoutResId, int viewId, Fragment fragment) {
42 | setContentView(layoutResId);
43 | mainLayout = (FrameLayout) findViewById(viewId);
44 | setInitialFragment(mainLayout, fragment);
45 | }
46 |
47 | /**
48 | * This method loads the initial fragment, it should be called inside
49 | * setInitialFragment().
50 | *
51 | * @param viewId - the Main view id.
52 | * @param fragment - the initial Fragment
53 | */
54 | protected void setInitialFragment(int viewId, Fragment fragment) {
55 | mainLayout = (FrameLayout) findViewById(viewId);
56 | setInitialFragment(mainLayout, fragment);
57 | }
58 |
59 | /**
60 | * This method loads the initial fragment
61 | *
62 | * @param view - the Main View, it is recommended to use a FrameLayout
63 | * @param fragment - the initial fragment
64 | */
65 | private void setInitialFragment(View view, Fragment fragment) {
66 | if(getCurrentFragment() == null) {
67 | FragmentManager fragmentManager = getSupportFragmentManager();
68 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
69 | fragmentTransaction.replace(view.getId(), fragment).commit();
70 | }
71 | }
72 |
73 | /**
74 | * This method replace the existing fragment with a current one. This new
75 | * fragment is added to the back stack.
76 | *
77 | * @param newFragment - The new Fragment that will replace the current visible fragment.
78 | */
79 | protected void replaceFragment(Fragment newFragment) {
80 | this.replaceFragment(newFragment, true);
81 | }
82 |
83 | /**
84 | * This method replace the existing fragment with a current one. This new
85 | * fragment could be added or not to the back stack.
86 | *
87 | * @param newFragment The new Fragment that will replace the current visible fragment.
88 | * @param addToBackStack True if the new Fragment should be added to the back stack, false otherwise.
89 | */
90 | protected void replaceFragment(Fragment newFragment, boolean addToBackStack) {
91 | FragmentManager fragmentManager = getSupportFragmentManager();
92 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
93 | if (addToBackStack) {
94 | fragmentTransaction.addToBackStack(null);
95 | }
96 | fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
97 | fragmentTransaction.replace(mainLayout.getId(), newFragment).commit();
98 | }
99 |
100 | /**
101 | * Returns the current showing fragment or null if no fragment is added.
102 | * @return the fragment previously added or null
103 | */
104 | protected Fragment getCurrentFragment() {
105 | return getSupportFragmentManager().findFragmentById(mainLayout.getId());
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/activity/DetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.test.activity;
2 |
3 | import android.content.Intent;
4 | import android.graphics.drawable.Drawable;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.app.ActivityCompat;
9 | import android.support.v4.app.ActivityOptionsCompat;
10 | import android.support.v4.app.NavUtils;
11 | import android.support.v4.util.Pair;
12 | import android.support.v7.widget.Toolbar;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 |
16 | import com.android.test.R;
17 | import com.android.test.fragment.DetailFragment;
18 | import com.android.test.view.ObservableScrollView;
19 | import com.android.test.view.VenueItemView;
20 |
21 |
22 | public class DetailActivity extends AbstractActionBarActivity implements DetailFragment.Callback {
23 |
24 | private Toolbar toolbar;
25 |
26 | private Drawable mActionBarBackgroundDrawable;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 |
32 | toolbar = (Toolbar) findViewById(R.id.material_toolbar);
33 |
34 | setSupportActionBar(toolbar);
35 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
36 |
37 | mActionBarBackgroundDrawable = getResources().getDrawable(R.color.md_green_500);
38 | mActionBarBackgroundDrawable.setAlpha(0);
39 |
40 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
41 | mActionBarBackgroundDrawable.setCallback(mDrawableCallback);
42 | }
43 |
44 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
45 | toolbar.setBackgroundDrawable(mActionBarBackgroundDrawable);
46 | }else {
47 | toolbar.setBackground(mActionBarBackgroundDrawable);
48 | }
49 |
50 | }
51 |
52 | private Drawable.Callback mDrawableCallback = new Drawable.Callback() {
53 | @Override
54 | public void invalidateDrawable(Drawable who) {
55 | toolbar.setBackgroundDrawable(who);
56 | }
57 |
58 | @Override
59 | public void scheduleDrawable(Drawable who, Runnable what, long when) {
60 | }
61 |
62 | @Override
63 | public void unscheduleDrawable(Drawable who, Runnable what) {
64 | }
65 | };
66 |
67 | @Override
68 | public void onSetupFadingActionBar(ObservableScrollView observableScrollView, final View header) {
69 | observableScrollView.setObservableScrollViewListener(new ObservableScrollView.ObservableScrollViewListener() {
70 | @Override
71 | public void onScrollChanged(int l, int t, int oldl, int oldt) {
72 | final int headerHeight = (header.getHeight() - toolbar.getHeight());
73 | final float ratio = (float) Math.min(Math.max(t, 0), headerHeight) / headerHeight;
74 | final int newAlpha = (int) (ratio * 255);
75 | mActionBarBackgroundDrawable.setAlpha(newAlpha);
76 | }
77 | });
78 | }
79 |
80 |
81 |
82 | @Nullable
83 | @Override
84 | public Intent getParentActivityIntent() {
85 | return super.getParentActivityIntent();
86 | }
87 |
88 | @Override
89 | protected void setInitialFragment() {
90 |
91 | String url = null;
92 | String name = null;
93 | String distance = null;
94 |
95 | if(getIntent().getExtras() != null) {
96 | Bundle bundle = getIntent().getExtras();
97 | url = bundle.getString(DetailFragment.ANIMATED_IMAGE);
98 | name = bundle.getString(DetailFragment.ANIMATED_NAME);
99 | distance = bundle.getString(DetailFragment.ANIMATED_DISTANCE);
100 | }
101 |
102 | setInitialFragment(R.layout.activity_main_overlay, R.id.container, DetailFragment.newInstance(url, name, distance));
103 | }
104 |
105 | @Override
106 | public boolean onOptionsItemSelected(MenuItem item) {
107 |
108 | switch (item.getItemId()) {
109 | case android.R.id.home:
110 | NavUtils.navigateUpTo(this, new Intent(this, ResultListActivity.class));
111 | animate();
112 | }
113 |
114 | return super.onOptionsItemSelected(item);
115 | }
116 |
117 | @Override
118 | public void onBackPressed() {
119 | super.onBackPressed();
120 | animate();
121 | }
122 |
123 | public static void startActivity(AbstractActionBarActivity activity, View transitionView, String url) {
124 | ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
125 | Pair.create(transitionView, DetailFragment.ANIMATED_IMAGE),
126 | Pair.create(transitionView, DetailFragment.ANIMATED_NAME),
127 | Pair.create(transitionView, DetailFragment.ANIMATED_DISTANCE));
128 |
129 | Intent intent = new Intent(activity, DetailActivity.class);
130 | intent.putExtra(DetailFragment.ANIMATED_IMAGE, url);
131 | intent.putExtra(DetailFragment.ANIMATED_NAME, ((VenueItemView)transitionView).getNameText() );
132 | intent.putExtra(DetailFragment.ANIMATED_DISTANCE, ((VenueItemView)transitionView).getDistanceText() );
133 |
134 | ActivityCompat.startActivity(activity, intent, options.toBundle());
135 | animate(activity);
136 | }
137 |
138 | private static void animate(AbstractActionBarActivity activity) {
139 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
140 | activity.overridePendingTransition(R.anim.bottom_in, R.anim.top_out);
141 | }
142 |
143 | }
144 |
145 | private void animate() {
146 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
147 | overridePendingTransition(R.anim.top_in, R.anim.bottom_out);
148 | }
149 |
150 | }
151 |
152 |
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/activity/ResultListActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.test.activity;
2 |
3 | import android.content.Intent;
4 | import android.location.Location;
5 | import android.os.Bundle;
6 | import android.support.v4.app.NavUtils;
7 | import android.support.v7.widget.Toolbar;
8 | import android.view.MenuItem;
9 | import android.view.View;
10 | import android.view.animation.AccelerateDecelerateInterpolator;
11 | import android.view.animation.Interpolator;
12 |
13 | import com.android.test.R;
14 | import com.android.test.domain.Venue;
15 | import com.android.test.fragment.ResultListFragment;
16 | import com.android.test.utils.DataHelper;
17 |
18 |
19 | public class ResultListActivity extends AbstractActionBarActivity implements ResultListFragment.Callback {
20 |
21 | private final int ANIM_DURATION = 200;
22 |
23 | private Toolbar toolbar;
24 |
25 | private Interpolator mInterpolator;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 |
31 | toolbar = (Toolbar) findViewById(R.id.material_toolbar);
32 | mInterpolator = new AccelerateDecelerateInterpolator();
33 |
34 | setSupportActionBar(toolbar);
35 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
36 | }
37 |
38 | @Override
39 | protected void setInitialFragment() {
40 |
41 | DataHelper dataHelper = null;
42 | String place = null;
43 | Location location = null;
44 |
45 | if(getIntent().getExtras() != null) {
46 | Bundle bundle = getIntent().getExtras();
47 | dataHelper = (DataHelper) bundle.getSerializable(ResultListFragment.DATA_HELPER);
48 | place = bundle.getString(ResultListFragment.PLACE);
49 | location = bundle.getParcelable(ResultListFragment.LOCATION);
50 | }
51 |
52 | setInitialFragment(R.layout.activity_main_overlay, R.id.container, ResultListFragment.newInstance(dataHelper, place, location));
53 | }
54 |
55 | @Override
56 | public boolean onOptionsItemSelected(MenuItem item) {
57 |
58 | switch (item.getItemId()) {
59 | case android.R.id.home:
60 | NavUtils.navigateUpTo(this, new Intent(this, SideBarActivity.class));
61 | }
62 |
63 | return super.onOptionsItemSelected(item);
64 | }
65 |
66 |
67 | @Override
68 | public void onItemClick(Venue venue, View view, String url) {
69 | DetailActivity.startActivity(this, view, url);
70 | }
71 |
72 | @Override
73 | public void onToolbarHide() {
74 | toolbar.animate().setInterpolator(mInterpolator)
75 | .setDuration(ANIM_DURATION)
76 | .translationY(-toolbar.getHeight());
77 | }
78 |
79 | @Override
80 | public void onToolbarShow() {
81 | toolbar.animate().setInterpolator(mInterpolator)
82 | .setDuration(ANIM_DURATION)
83 | .translationY(0);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/activity/SideBarActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.test.activity;
2 |
3 | import android.content.Intent;
4 | import android.content.res.Configuration;
5 | import android.location.Location;
6 | import android.os.Bundle;
7 | import android.support.v4.widget.DrawerLayout;
8 | import android.support.v7.app.ActionBarDrawerToggle;
9 | import android.support.v7.widget.Toolbar;
10 | import android.view.Gravity;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.widget.AdapterView;
14 | import android.widget.ArrayAdapter;
15 | import android.widget.ListView;
16 |
17 | import com.android.test.R;
18 | import com.android.test.domain.Venue;
19 | import com.android.test.fragment.MainFragment;
20 | import com.android.test.fragment.ResultListFragment;
21 | import com.android.test.utils.DataHelper;
22 | import com.android.test.view.SideBarCallback;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 | import java.util.Set;
27 |
28 |
29 | public class SideBarActivity extends AbstractActionBarActivity implements MainFragment.Callback, AdapterView.OnItemClickListener {
30 |
31 | private Toolbar toolbar;
32 |
33 | private DrawerLayout drawerLayout;
34 |
35 | private ListView listView;
36 |
37 | private ActionBarDrawerToggle drawerToggle;
38 | private SideBarCallback sideBarCallback;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 |
44 | toolbar = (Toolbar) findViewById(R.id.material_toolbar);
45 | drawerLayout = (DrawerLayout) findViewById(R.id.activity_main_drawer_layout);
46 | listView = (ListView) findViewById(R.id.activity_side_bar_list_view);
47 |
48 | setSupportActionBar(toolbar);
49 | getSupportActionBar().setHomeButtonEnabled(true);
50 | toolbar.setNavigationIcon(R.drawable.ic_action_navigation_menu);
51 | setupSideBar();
52 | }
53 |
54 | @Override
55 | protected void setInitialFragment() {
56 | setInitialFragment(R.layout.activity_side_bar, R.id.container, MainFragment.newInstance());
57 | }
58 |
59 | // @Override
60 | // public boolean onCreateOptionsMenu(Menu menu) {
61 | // getMenuInflater().inflate(R.menu.search_menu, menu);
62 | // return true;
63 | // }
64 |
65 | private void setupSideBar() {
66 | if (toolbar != null) {
67 | drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);
68 | toolbar.setNavigationOnClickListener(new View.OnClickListener() {
69 | @Override
70 | public void onClick(View view) {
71 | if (drawerLayout.isDrawerOpen(Gravity.START)) {
72 | drawerLayout.closeDrawer(Gravity.START);
73 | } else {
74 | drawerLayout.openDrawer(Gravity.START);
75 | }
76 | }
77 | });
78 | }
79 |
80 |
81 | drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close) {
82 | /** Called when a drawer has settled in a completely closed state. */
83 | public void onDrawerClosed(View view) {
84 | supportInvalidateOptionsMenu();
85 | }
86 |
87 | /** Called when a drawer has settled in a completely open state. */
88 | public void onDrawerOpened(View drawerView) {
89 | supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
90 | }
91 | };
92 |
93 | drawerLayout.setDrawerListener(drawerToggle);
94 |
95 | }
96 |
97 | @Override
98 | public void onBackPressed() {
99 | if(drawerLayout.isDrawerOpen(Gravity.START)) {
100 | drawerLayout.closeDrawer(Gravity.START);
101 | }else {
102 | super.onBackPressed();
103 | }
104 | }
105 |
106 | @Override
107 | public boolean onOptionsItemSelected(MenuItem item) {
108 | if (drawerToggle.onOptionsItemSelected(item)) {
109 | return true;
110 | }
111 |
112 | return super.onOptionsItemSelected(item);
113 | }
114 |
115 |
116 | @Override
117 | protected void onPostCreate(Bundle savedInstanceState) {
118 | super.onPostCreate(savedInstanceState);
119 | drawerToggle.syncState();
120 | }
121 |
122 |
123 | @Override
124 | public void onConfigurationChanged(Configuration newConfig) {
125 | super.onConfigurationChanged(newConfig);
126 | drawerToggle.onConfigurationChanged(newConfig);
127 |
128 | }
129 |
130 | @Override
131 | public void onResult(List venues, Location currentLocation, String place) {
132 | // ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, transitionView, EXTRA_IMAGE);
133 | // Intent intent = new Intent(this, ResultListActivity.class);
134 | // intent.putExtra(EXTRA_IMAGE, url);
135 | // ActivityCompat.startActivity(activity, intent, options.toBundle());
136 |
137 | Intent intent = new Intent(this, ResultListActivity.class);
138 | Bundle bundle = new Bundle();
139 | bundle.putSerializable(ResultListFragment.DATA_HELPER, new DataHelper(venues));
140 | bundle.putString(ResultListFragment.PLACE, place);
141 |
142 | if(currentLocation != null) {
143 | bundle.putParcelable(ResultListFragment.LOCATION, currentLocation);
144 | }
145 |
146 | intent.putExtras(bundle);
147 | startActivity(intent);
148 | }
149 |
150 | @Override
151 | public void loadSavedPlaces(Set savedPlaces, SideBarCallback sideBarCallback) {
152 | this.sideBarCallback = sideBarCallback;
153 | listView.setOnItemClickListener(this);
154 | List list = new ArrayList(savedPlaces);
155 | ArrayAdapter savedPlacesAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, list);
156 | listView.setAdapter(savedPlacesAdapter);
157 | }
158 |
159 | @Override
160 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
161 | String place = (String) parent.getItemAtPosition(position);
162 | this.sideBarCallback.onSideBarItemClick(place);
163 | drawerLayout.closeDrawer(Gravity.START);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/adapter/VenueRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.android.test.adapter;
2 |
3 | import android.location.Location;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.android.test.domain.Venue;
9 | import com.android.test.view.VenueItemView;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Created by Nicolas Jafelle on 10/28/14.
15 | */
16 | public class VenueRecyclerAdapter extends RecyclerView.Adapter {
17 |
18 | private enum ViewTypes {
19 | FIRST_VIEW,
20 | REST_VIEW;
21 | }
22 |
23 | public interface RecyclerViewListener {
24 | void onItemClickListener(View view , int position);
25 |
26 | }
27 |
28 | private List venues;
29 | private Location currentLocation;
30 | private RecyclerViewListener recyclerViewListener;
31 |
32 | public VenueRecyclerAdapter(List venues, Location currentLocation, RecyclerViewListener recyclerViewListener) {
33 | this.venues = venues;
34 | this.currentLocation = currentLocation;
35 | this.recyclerViewListener = recyclerViewListener;
36 | }
37 |
38 | @Override
39 | public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
40 |
41 | // create a new view
42 | VenueItemView view = new VenueItemView(viewGroup.getContext());
43 | // set the view's size, margins, paddings and layout parameters
44 | if(viewType == ViewTypes.FIRST_VIEW.ordinal()) {
45 | view.setFirst();
46 | }
47 |
48 | return new ViewHolder(view);
49 | }
50 |
51 | @Override
52 | public void onBindViewHolder(ViewHolder viewHolder, int position) {
53 | final Venue rowData = venues.get(position);
54 | viewHolder.venueItemView.fillData(rowData, currentLocation);
55 | }
56 |
57 | @Override
58 | public int getItemCount() {
59 | return venues.size();
60 | }
61 |
62 | @Override
63 | public int getItemViewType(int position) {
64 | if(position == 0) {
65 | return ViewTypes.FIRST_VIEW.ordinal();
66 | }else {
67 | return ViewTypes.REST_VIEW.ordinal();
68 | }
69 |
70 | }
71 |
72 | public Venue getItemAtPosition(int position) {
73 | return venues.get(position);
74 | }
75 |
76 |
77 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
78 |
79 | private final VenueItemView venueItemView;
80 |
81 | public ViewHolder(VenueItemView itemView) {
82 | super(itemView);
83 | venueItemView = itemView;
84 | venueItemView.setOnClickListener(this);
85 | }
86 |
87 | @Override
88 | public void onClick(View v) {
89 | recyclerViewListener.onItemClickListener(v, getPosition());
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/client/FoursquareClient.java:
--------------------------------------------------------------------------------
1 | package com.android.test.client;
2 |
3 | import com.android.test.dto.VenueDto;
4 | import com.google.inject.Singleton;
5 | import com.squareup.okhttp.OkHttpClient;
6 |
7 | import retrofit.RestAdapter;
8 | import retrofit.client.OkClient;
9 |
10 | /**
11 | * This class is the responsable to connect to the API. Here lies all the
12 | * connections between the client and the server.
13 | * As Jake Wharton said:
14 | * "RestAdapter and the created instances should be treated as singletons"
15 | * @author nicolasjafelle
16 | */
17 | @Singleton
18 | public class FoursquareClient {
19 |
20 | private static final String BASE_URL = "https://api.foursquare.com/v2";
21 |
22 | private RestAdapter restAdapter;
23 | private IFoursquareClient foursquareClient;
24 |
25 | public FoursquareClient() {
26 | if (restAdapter == null || foursquareClient == null) {
27 |
28 | OkHttpClient okHttpClient = new OkHttpClient();
29 |
30 | restAdapter = new RestAdapter.Builder()
31 | .setEndpoint(BASE_URL)
32 | .setClient(new OkClient(okHttpClient))
33 | .setLogLevel(RestAdapter.LogLevel.FULL)
34 | .build();
35 |
36 | foursquareClient = restAdapter.create(IFoursquareClient.class);
37 | }
38 | }
39 |
40 |
41 | public VenueDto searchForVenues(String criteria) {
42 | String token = "HDQVML4JWDJNHHKCSRPN0MPYUFEMJJEXH3C34FTCPYUOR5OP";
43 | long v = 20130417;
44 |
45 | return foursquareClient.searchForVenues(criteria, token, v);
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/client/IFoursquareClient.java:
--------------------------------------------------------------------------------
1 | package com.android.test.client;
2 |
3 | import com.android.test.dto.VenueDto;
4 |
5 | import retrofit.http.GET;
6 | import retrofit.http.Query;
7 |
8 | /**
9 | * Created by nicolas on 12/22/13.
10 | */
11 | public interface IFoursquareClient {
12 |
13 | @GET("/venues/search")
14 | VenueDto searchForVenues(@Query("near") String place, @Query("oauth_token") String token, @Query("v") long v);
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dialog/DialogFragmentHelper.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dialog;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.v4.app.DialogFragment;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentActivity;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v4.app.FragmentTransaction;
10 |
11 | /**
12 | * Dialog fragment helper
13 | */
14 | public abstract class DialogFragmentHelper extends DialogFragment {
15 |
16 | private static final String TAG = "dialog_fragment_helper";
17 |
18 | /**
19 | * Show dialog
20 | */
21 | public static void show(FragmentActivity activity, DialogFragment fragment, Bundle arguments) {
22 | FragmentManager manager = activity.getSupportFragmentManager();
23 | FragmentTransaction transaction = manager.beginTransaction();
24 | Fragment current = manager.findFragmentByTag(TAG);
25 | if (current != null) {
26 | transaction.remove(current);
27 | //transaction.addToBackStack(null);
28 | transaction.commit();
29 | }
30 | if(fragment.getArguments() == null) {
31 | fragment.setArguments(arguments);
32 | }else {
33 | fragment.getArguments().putAll(arguments);
34 | }
35 |
36 | fragment.show(manager, TAG);
37 | }
38 |
39 | /**
40 | * Dismiss current DialogFragment
41 | * @param activity
42 | */
43 | public static void dismissDialog(FragmentActivity activity){
44 | Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(TAG);
45 | if (prev != null) {
46 | DialogFragment df = (DialogFragment) prev;
47 | df.dismissAllowingStateLoss();
48 | }
49 | }
50 |
51 | /**
52 | * Dismiss current DialogFragment
53 | * @param context
54 | */
55 | public static void dismissDialog(Context context){
56 | Fragment prev = ((FragmentActivity)context).getSupportFragmentManager().findFragmentByTag(TAG);
57 | if (prev != null) {
58 | DialogFragment df = (DialogFragment) prev;
59 | df.dismissAllowingStateLoss();
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dialog/ProgressDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dialog;
2 |
3 | import android.app.Dialog;
4 | import android.app.ProgressDialog;
5 | import android.content.DialogInterface;
6 | import android.os.Bundle;
7 | import android.support.v4.app.DialogFragment;
8 | import android.view.View;
9 |
10 |
11 |
12 | /**
13 | * This Dialog is just an indeterminet progress, typically used for Background Tasks.
14 | */
15 | public class ProgressDialogFragment extends DialogFragment {
16 |
17 | /**
18 | * Callback used when the user cancel or press the back button to cancel the task.
19 | */
20 | public interface ProgressDialogFragmentListener {
21 | void onCancel();
22 | }
23 |
24 | public static ProgressDialogFragment newInstance() {
25 | return new ProgressDialogFragment();
26 | }
27 |
28 | public static final String MESSAGE = "message";
29 | private ProgressDialogFragmentListener listener;
30 |
31 | public void setProgressDialogFragmentListener(ProgressDialogFragmentListener listener) {
32 | this.listener = listener;
33 | }
34 |
35 | @Override
36 | public void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setRetainInstance(true);
39 | }
40 |
41 | @Override
42 | public void onViewCreated(View view, Bundle savedInstanceState) {
43 | super.onViewCreated(view, savedInstanceState);
44 | }
45 |
46 |
47 | @Override
48 | public Dialog onCreateDialog(Bundle savedInstanceState) {
49 | final ProgressDialog dialog = new ProgressDialog(getActivity());
50 |
51 | dialog.setMessage(getArguments().getString(MESSAGE));
52 | dialog.setIndeterminate(true);
53 | dialog.setCancelable(true);
54 | dialog.setCanceledOnTouchOutside(false);
55 | return dialog;
56 | }
57 |
58 | public boolean isShowing() {
59 | boolean isShowing = false;
60 | if(getDialog() != null) {
61 | isShowing = getDialog().isShowing();
62 | }
63 | return isShowing;
64 | }
65 |
66 | /**
67 | * Workaround for an open bug in DialogFragment.
68 | * https://code.google.com/p/android/issues/detail?id=17423
69 | */
70 | @Override
71 | public void onDestroyView() {
72 | if(getDialog() != null && getRetainInstance()) {
73 | getDialog().setDismissMessage(null);
74 | }
75 | super.onDestroyView();
76 | }
77 |
78 | public void setMessage(int resId) {
79 | ((ProgressDialog)getDialog()).setMessage(getString(resId));
80 | }
81 |
82 | @Override
83 | public void onCancel(DialogInterface dialog) {
84 | super.onCancel(dialog);
85 | if (listener != null) {
86 | listener.onCancel();
87 | }
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/domain/Contact.java:
--------------------------------------------------------------------------------
1 | package com.android.test.domain;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by nicolas on 12/22/13.
7 | */
8 | public class Contact implements Serializable {
9 |
10 | private static final long serialVersionUID = 1L;
11 |
12 | private String formattedPhone;
13 |
14 | public String getFormattedPhone() {
15 | return formattedPhone;
16 | }
17 |
18 | public void setFormattedPhone(String formattedPhone) {
19 | this.formattedPhone = formattedPhone;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/domain/Location.java:
--------------------------------------------------------------------------------
1 | package com.android.test.domain;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by nicolas on 12/22/13.
7 | */
8 | public class Location implements Serializable {
9 |
10 | private static final long serialVersionUID = 1L;
11 |
12 | private String address;
13 | private double lat;
14 | private double lng;
15 | private String postalCode;
16 | private String cc;
17 | private String city;
18 | private String state;
19 | private String country;
20 |
21 | public String getAddress() {
22 | return address;
23 | }
24 |
25 | public void setAddress(String address) {
26 | this.address = address;
27 | }
28 |
29 | public double getLat() {
30 | return lat;
31 | }
32 |
33 | public void setLat(double lat) {
34 | this.lat = lat;
35 | }
36 |
37 | public double getLng() {
38 | return lng;
39 | }
40 |
41 | public void setLng(double lng) {
42 | this.lng = lng;
43 | }
44 |
45 | public String getPostalCode() {
46 | return postalCode;
47 | }
48 |
49 | public void setPostalCode(String postalCode) {
50 | this.postalCode = postalCode;
51 | }
52 |
53 | public String getCc() {
54 | return cc;
55 | }
56 |
57 | public void setCc(String cc) {
58 | this.cc = cc;
59 | }
60 |
61 | public String getCity() {
62 | return city;
63 | }
64 |
65 | public void setCity(String city) {
66 | this.city = city;
67 | }
68 |
69 | public String getState() {
70 | return state;
71 | }
72 |
73 | public void setState(String state) {
74 | this.state = state;
75 | }
76 |
77 | public String getCountry() {
78 | return country;
79 | }
80 |
81 | public void setCountry(String country) {
82 | this.country = country;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/domain/Venue.java:
--------------------------------------------------------------------------------
1 | package com.android.test.domain;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by nicolas on 12/22/13.
7 | */
8 | public class Venue implements Serializable {
9 |
10 | private static final long serialVersionUID = 1L;
11 |
12 | private String id;
13 | private String name;
14 | private Location location;
15 | private Contact contact;
16 | // for this test we don't need additional attributes like categories and stats.
17 |
18 | public String getId() {
19 | return id;
20 | }
21 |
22 | public void setId(String id) {
23 | this.id = id;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public Location getLocation() {
35 | return location;
36 | }
37 |
38 | public void setLocation(Location location) {
39 | this.location = location;
40 | }
41 |
42 | public Contact getContact() {
43 | return contact;
44 | }
45 |
46 | public void setContact(Contact contact) {
47 | this.contact = contact;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dto/ErrorType.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dto;
2 |
3 | /**
4 | * Created by nicolas on 12/22/13.
5 | */
6 | public enum ErrorType {
7 |
8 | failed_geocode;
9 | //TODO add more error types
10 | }
11 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dto/FoursquareApiErrorDto.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dto;
2 |
3 | /**
4 | * Created by nicolas on 12/22/13.
5 | */
6 | public class FoursquareApiErrorDto {
7 |
8 | private Meta meta;
9 |
10 | public Meta getMeta() {
11 | return meta;
12 | }
13 |
14 | public void setMeta(Meta meta) {
15 | this.meta = meta;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dto/FoursquareDto.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dto;
2 |
3 |
4 | /**
5 | * FoursquareDto
6 | * Created by nicolas on 12/22/13.
7 | */
8 | public abstract class FoursquareDto {
9 |
10 | private Meta meta;
11 | private Response response;
12 | // for this test we don't need additional attributes like confident or geocode.
13 |
14 |
15 | public Meta getMeta() {
16 | return meta;
17 | }
18 |
19 | public void setMeta(Meta meta) {
20 | this.meta = meta;
21 | }
22 |
23 | public Response getResponse() {
24 | return response;
25 | }
26 |
27 | public void setResponse(Response response) {
28 | this.response = response;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dto/Meta.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dto;
2 |
3 | /**
4 | * Created by nicolas on 12/22/13.
5 | */
6 | public class Meta {
7 |
8 | private int code;
9 | private ErrorType errorType;
10 |
11 | public int getCode() {
12 | return code;
13 | }
14 |
15 | public void setCode(int code) {
16 | this.code = code;
17 | }
18 |
19 | public ErrorType getErrorType() {
20 | return errorType;
21 | }
22 |
23 | public void setErrorType(ErrorType errorType) {
24 | this.errorType = errorType;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dto/Response.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dto;
2 |
3 | import com.android.test.domain.Venue;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Created by nicolas on 12/22/13.
9 | */
10 | public class Response {
11 |
12 | private List venues;
13 |
14 | public List getVenues() {
15 | return venues;
16 | }
17 |
18 | public void setVenues(List venues) {
19 | this.venues = venues;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/dto/VenueDto.java:
--------------------------------------------------------------------------------
1 | package com.android.test.dto;
2 |
3 | /**
4 | * Created by nicolas on 12/22/13.
5 | */
6 | public class VenueDto extends FoursquareDto {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/fragment/AbstractFragment.java:
--------------------------------------------------------------------------------
1 | package com.android.test.fragment;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v7.app.ActionBarActivity;
7 |
8 | import com.android.test.AndroidDemoApplication;
9 |
10 |
11 | public abstract class AbstractFragment extends Fragment {
12 |
13 | protected T callbacks;
14 |
15 | @Override
16 | public void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setHasOptionsMenu(true);
19 | AndroidDemoApplication.injectMembers(this);
20 | // setRetainInstance(true);
21 | }
22 |
23 | @Override
24 | public void onAttach(Activity activity) {
25 | super.onAttach(activity);
26 | try {
27 | callbacks = (T) activity;
28 | } catch (ClassCastException e) {
29 | throw new ClassCastException(activity.toString() + " must implement Callback interface");
30 | }
31 | }
32 |
33 |
34 | @Override
35 | public void onDetach() {
36 | super.onDetach();
37 | this.callbacks = null;
38 | }
39 |
40 |
41 | protected ActionBarActivity getActionBarActivity() {
42 | return (ActionBarActivity) getActivity();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/fragment/DetailFragment.java:
--------------------------------------------------------------------------------
1 | package com.android.test.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.view.ViewCompat;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.android.test.R;
13 | import com.android.test.view.ObservableScrollView;
14 | import com.squareup.picasso.Picasso;
15 |
16 |
17 | public class DetailFragment extends AbstractFragment {
18 |
19 | public static final String ANIMATED_IMAGE = "image";
20 | public static final String ANIMATED_NAME = "name";
21 | public static final String ANIMATED_DISTANCE = "distance";
22 |
23 | public interface Callback {
24 | void onSetupFadingActionBar(ObservableScrollView observableScrollView, final View header);
25 | }
26 |
27 | private ObservableScrollView scrollview;
28 |
29 | private ImageView imageView;
30 |
31 | private TextView nameView;
32 |
33 | private TextView distanceView;
34 |
35 | private String url;
36 |
37 | private String name;
38 |
39 | private String distance;
40 |
41 |
42 | public static Fragment newInstance(String url, String name, String distance) {
43 | Bundle args = new Bundle();
44 | args.putString(DetailFragment.ANIMATED_IMAGE, url);
45 | args.putString(DetailFragment.ANIMATED_NAME, name);
46 | args.putString(DetailFragment.ANIMATED_DISTANCE, distance);
47 |
48 | Fragment f = new DetailFragment();
49 | f.setArguments(args);
50 | return f;
51 | }
52 |
53 | @Override
54 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
55 | View view = inflater.inflate(R.layout.fragment_detail, container, false);
56 |
57 | scrollview = (ObservableScrollView) view.findViewById(R.id.fragment_detail_observable_scroll_view);
58 | imageView = (ImageView) view.findViewById(R.id.fragment_detail_image_view);
59 | nameView = (TextView) view.findViewById(R.id.fragment_detail_name);
60 | distanceView = (TextView) view.findViewById(R.id.fragment_detail_distance);
61 |
62 | return view;
63 | }
64 |
65 | @Override
66 | public void onViewCreated(View view, Bundle savedInstanceState) {
67 | super.onViewCreated(view, savedInstanceState);
68 |
69 | if(getArguments() != null) {
70 | url = getArguments().getString(ANIMATED_IMAGE);
71 | name = getArguments().getString(ANIMATED_NAME);
72 | distance = getArguments().getString(ANIMATED_DISTANCE);
73 | }
74 |
75 |
76 | callbacks.onSetupFadingActionBar(scrollview, imageView);
77 |
78 | ViewCompat.setTransitionName(imageView, ANIMATED_IMAGE);
79 | ViewCompat.setTransitionName(nameView, ANIMATED_NAME);
80 | ViewCompat.setTransitionName(distanceView, ANIMATED_DISTANCE);
81 |
82 | Picasso.with(getActivity())
83 | .load(url)
84 | .into(imageView);
85 |
86 | nameView.setText(name);
87 | distanceView.setText(distance);
88 |
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/fragment/MainFragment.java:
--------------------------------------------------------------------------------
1 | package com.android.test.fragment;
2 |
3 | import android.content.Context;
4 | import android.location.Location;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.AppCompatButton;
8 | import android.support.v7.widget.AppCompatEditText;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.view.inputmethod.InputMethodManager;
13 | import android.widget.Button;
14 | import android.widget.EditText;
15 | import android.widget.Toast;
16 |
17 | import com.android.test.AndroidDemoApplication;
18 | import com.android.test.R;
19 | import com.android.test.client.FoursquareClient;
20 | import com.android.test.dialog.DialogFragmentHelper;
21 | import com.android.test.dialog.ProgressDialogFragment;
22 | import com.android.test.domain.Venue;
23 | import com.android.test.dto.ErrorType;
24 | import com.android.test.dto.FoursquareApiErrorDto;
25 | import com.android.test.location.GPSTracker;
26 | import com.android.test.otto.OttoBus;
27 | import com.android.test.otto.VenueResultEvent;
28 | import com.android.test.otto.VenueSearchEvent;
29 | import com.android.test.qachee.QacheeData;
30 | import com.android.test.session.SessionManager;
31 | import com.android.test.task.FoursquareAsyncTask;
32 | import com.android.test.task.VenueBackgroundTask;
33 | import com.android.test.task.event.OnApiErrorEvent;
34 | import com.android.test.task.event.OnFinallyEvent;
35 | import com.android.test.task.event.OnPreExecuteEvent;
36 | import com.android.test.view.SideBarCallback;
37 | import com.qachee.QacheeManager;
38 | import com.squareup.otto.Subscribe;
39 |
40 | import java.util.List;
41 | import java.util.Set;
42 |
43 | import javax.inject.Inject;
44 |
45 | /**
46 | * MainFragment
47 | * Created by nicolas on 12/22/13.
48 | */
49 | public class MainFragment extends AbstractFragment
50 | implements SideBarCallback, ProgressDialogFragment.ProgressDialogFragmentListener {
51 |
52 |
53 |
54 |
55 | public interface Callback {
56 | void onResult(List venues, Location currentLocation, String place);
57 | void loadSavedPlaces(Set savedPlaces, SideBarCallback sideBarCallback);
58 | }
59 |
60 | private AppCompatEditText editText;
61 |
62 | private AppCompatButton searchButton;
63 |
64 | private FoursquareAsyncTask asyncTask;
65 |
66 | @Inject
67 | private SessionManager sessionManager;
68 |
69 | @Inject
70 | private FoursquareClient foursquareClient;
71 |
72 | @Inject
73 | private OttoBus ottoBus;
74 |
75 | private ProgressDialogFragment progressDialog;
76 |
77 | @Inject
78 | private GPSTracker gpsTracker;
79 |
80 | @Override
81 | public void onCreate(Bundle savedInstanceState) {
82 | super.onCreate(savedInstanceState);
83 | }
84 |
85 | public static Fragment newInstance() {
86 | return new MainFragment();
87 | }
88 |
89 | @Override
90 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
91 | View view = inflater.inflate(R.layout.fragment_main, container, false);
92 |
93 | editText = (AppCompatEditText) view.findViewById(R.id.fragment_main_edittext);
94 | searchButton = (AppCompatButton) view.findViewById(R.id.fragment_main_button);
95 |
96 | return view;
97 | }
98 |
99 | @Override
100 | public void onViewCreated(View view, Bundle savedInstanceState) {
101 | super.onViewCreated(view, savedInstanceState);
102 |
103 | progressDialog = ProgressDialogFragment.newInstance();
104 |
105 | searchButton.setOnClickListener(onClickListener);
106 | }
107 |
108 | @Override
109 | public void onResume() {
110 | super.onResume();
111 | loadSavedPlaces();
112 | }
113 |
114 | private void createProgressDialog(int resId) {
115 | Bundle arguments = new Bundle();
116 | progressDialog = ProgressDialogFragment.newInstance();
117 | progressDialog.setProgressDialogFragmentListener(this);
118 | arguments.putString(ProgressDialogFragment.MESSAGE, getString(resId));
119 | DialogFragmentHelper.show(getActivity(), progressDialog, arguments);
120 | }
121 |
122 | private View.OnClickListener onClickListener = new View.OnClickListener() {
123 | @Override
124 | public void onClick(View v) {
125 | String place = editText.getText().toString().trim();
126 |
127 | if(place == null || place.length() == 0) {
128 | Toast.makeText(getActivity(), R.string.edit_text_empty, Toast.LENGTH_SHORT).show();
129 | }else {
130 | // check if GPS enabled
131 | if(gpsTracker.canGetLocation()){
132 | postVenueSearchEvent(place);
133 | }else{
134 | gpsTracker.showSettingsAlert();
135 | }
136 | }
137 | }
138 | };
139 |
140 |
141 | @Override
142 | public void onSideBarItemClick(String text) {
143 | if(gpsTracker.canGetLocation()){
144 | postVenueSearchEvent(text);
145 | }else{
146 | gpsTracker.showSettingsAlert();
147 | }
148 | }
149 |
150 | private void postVenueSearchEvent(String text) {
151 | ottoBus.post(new VenueSearchEvent(text));
152 | }
153 |
154 | private void loadSavedPlaces() {
155 | Set savedPlaces = sessionManager.getSavedPlaces();
156 |
157 | if(!savedPlaces.isEmpty()) {
158 | callbacks.loadSavedPlaces(savedPlaces, this);
159 | }
160 | }
161 |
162 | @Override
163 | public void onStart() {
164 | super.onStart();
165 | ottoBus.register(this);
166 | }
167 |
168 | @Override
169 | public void onStop() {
170 | super.onPause();
171 | ottoBus.unregister(this);
172 | }
173 |
174 | @Override
175 | public void onDestroy() {
176 | super.onDestroy();
177 | gpsTracker.stopUsingGPS();
178 | }
179 |
180 |
181 | @Override
182 | public void onCancel() {
183 | cancelTask();
184 | }
185 |
186 | private void cancelTask() {
187 | if(asyncTask != null && !asyncTask.isCancelled()) {
188 | asyncTask.cancel(true);
189 | }
190 | }
191 |
192 | private void closeKeyboard() {
193 | InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(
194 | Context.INPUT_METHOD_SERVICE);
195 | imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
196 | }
197 |
198 | @Inject
199 | AndroidDemoApplication application;
200 |
201 | /* ********************************************************* */
202 | /* **************** Otto Subscribers *********************** */
203 | /* ********************************************************* */
204 |
205 | @Subscribe
206 | public void searchForVenues(VenueSearchEvent event) {
207 |
208 | QacheeData data = (QacheeData) QacheeManager.getInstance().get(event.place, true);
209 |
210 | if(data == null) {
211 | asyncTask = new VenueBackgroundTask(event.place, gpsTracker.getLocation());
212 | asyncTask.execute();
213 | }else {
214 | ottoBus.post(new VenueResultEvent(data.venues, event.place, gpsTracker.getLocation()));
215 | }
216 | }
217 |
218 | @Subscribe
219 | public void resultVenues(VenueResultEvent event) {
220 | if(event.venues == null || event.venues.size() == 0) {
221 | Toast.makeText(getActivity(), R.string.no_results_found, Toast.LENGTH_SHORT).show();
222 | }else {
223 | QacheeManager.getInstance().add(new QacheeData(event.place, event.venues));
224 | callbacks.onResult(event.venues, event.location, event.place);
225 | }
226 | }
227 |
228 | @Subscribe
229 | public void onPreExecute(OnPreExecuteEvent event) {
230 | createProgressDialog(R.string.connecting_to_foursquare);
231 | }
232 |
233 | @Subscribe
234 | public void onApiError(OnApiErrorEvent event) {
235 | FoursquareApiErrorDto errorDto = event.errorDto;
236 |
237 | if(errorDto.getMeta().getErrorType() == ErrorType.failed_geocode) {
238 | Toast.makeText(getActivity(), R.string.no_results_found, Toast.LENGTH_SHORT).show();
239 | }else {
240 | Toast.makeText(getActivity(), R.string.unknown_error, Toast.LENGTH_SHORT).show();
241 | }
242 | }
243 |
244 | @Subscribe
245 | public void onFinally(OnFinallyEvent event) {
246 | closeKeyboard();
247 | DialogFragmentHelper.dismissDialog(getActivity());
248 | }
249 |
250 |
251 | }
252 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/fragment/ResultListFragment.java:
--------------------------------------------------------------------------------
1 | package com.android.test.fragment;
2 |
3 | import android.location.Location;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v7.widget.DefaultItemAnimator;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.util.Log;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.Toast;
14 |
15 | import com.android.test.R;
16 | import com.android.test.adapter.VenueRecyclerAdapter;
17 | import com.android.test.domain.Venue;
18 | import com.android.test.session.SessionManager;
19 | import com.android.test.utils.DataHelper;
20 | import com.melnykov.fab.FloatingActionButton;
21 |
22 | import javax.inject.Inject;
23 |
24 |
25 | public class ResultListFragment extends AbstractFragment
26 | implements VenueRecyclerAdapter.RecyclerViewListener {
27 |
28 | public static final String DATA_HELPER = "data_helper";
29 | public static final String PLACE = "place";
30 | public static final String LOCATION = "location";
31 |
32 |
33 |
34 | public interface Callback {
35 | void onItemClick(Venue venue, View view, String url);
36 | void onToolbarHide();
37 | void onToolbarShow();
38 | }
39 |
40 | private DataHelper dataHelper;
41 |
42 | private String place;
43 |
44 | private Location currentLocation;
45 |
46 | private FloatingActionButton fab;
47 |
48 | private RecyclerView recyclerView;
49 |
50 | @Inject
51 | private SessionManager sessionManager;
52 |
53 |
54 | private VenueRecyclerAdapter adapter;
55 |
56 |
57 | public static Fragment newInstance(DataHelper dataHelper, String place, Location currentLocation) {
58 | Bundle bundle = new Bundle();
59 | bundle.putSerializable(DATA_HELPER, dataHelper);
60 | bundle.putString(PLACE, place);
61 | bundle.putParcelable(LOCATION, currentLocation);
62 |
63 | Fragment f = new ResultListFragment();
64 | f.setArguments(bundle);
65 |
66 | return f;
67 | }
68 |
69 | @Override
70 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
71 | View view = inflater.inflate(R.layout.fragment_result_list, container, false);
72 |
73 | fab = (FloatingActionButton) view.findViewById(R.id.fragment_result_list_floating_button);
74 | recyclerView = (RecyclerView) view.findViewById(R.id.fragment_result_list_recyclerview);
75 |
76 | return view;
77 | }
78 |
79 | @Override
80 | public void onViewCreated(View view, Bundle savedInstanceState) {
81 | super.onViewCreated(view, savedInstanceState);
82 |
83 | if(getArguments() != null) {
84 | dataHelper = (DataHelper) getArguments().getSerializable(DATA_HELPER);
85 | place = getArguments().getString(PLACE);
86 | currentLocation = getArguments().getParcelable(LOCATION);
87 | }
88 |
89 | setupRecyclerView();
90 | setupFab();
91 | }
92 |
93 | private void setupFab() {
94 | fab.setOnClickListener(new View.OnClickListener() {
95 | @Override
96 | public void onClick(View v) {
97 | sessionManager.savePlace(place);
98 |
99 | Toast.makeText(getActivity(), getString(R.string.location_saved_open_the_side_bar_to_see_it, place),
100 | Toast.LENGTH_SHORT).show();
101 | }
102 | });
103 | }
104 |
105 | private void setupRecyclerView() {
106 | recyclerView.setHasFixedSize(true);
107 |
108 | // use a linear layout manager
109 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this.getActivity());
110 |
111 | recyclerView.setLayoutManager(layoutManager);
112 | recyclerView.setItemAnimator(new DefaultItemAnimator());
113 |
114 | adapter = new VenueRecyclerAdapter(dataHelper.getList(), currentLocation, this);
115 | recyclerView.setAdapter(adapter);
116 |
117 |
118 | recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
119 |
120 | private static final int HIDE_THRESHOLD = 10;
121 | private int scrolledDistance = 0;
122 | private boolean isShowing = true;
123 |
124 | @Override
125 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
126 | super.onScrollStateChanged(recyclerView, newState);
127 | }
128 |
129 | @Override
130 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
131 | super.onScrolled(recyclerView, dx, dy);
132 |
133 | int firstVisibleItem = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
134 |
135 | if (firstVisibleItem == 0) {
136 | if (!isShowing) {
137 | callbacks.onToolbarShow();
138 | fab.show();
139 | isShowing = true;
140 | }
141 | }else if (scrolledDistance > HIDE_THRESHOLD && isShowing) {
142 | callbacks.onToolbarHide();
143 | fab.hide();
144 | isShowing = false;
145 | scrolledDistance = 0;
146 |
147 | } else if (scrolledDistance < -HIDE_THRESHOLD && !isShowing) {
148 | callbacks.onToolbarShow();
149 | fab.show();
150 | isShowing = true;
151 | scrolledDistance = 0;
152 | }
153 |
154 | if((isShowing && dy > 0) || (!isShowing && dy < 0)) {
155 | scrolledDistance = scrolledDistance + dy;
156 | Log.i("RECYCLER VIEW", "CURRENT AMOUNT VERTICAL SCROLL = " + scrolledDistance);
157 | }
158 | }
159 |
160 | });
161 | }
162 |
163 | @Override
164 | public void onItemClickListener(View view, int position) {
165 | Venue venue = adapter.getItemAtPosition(position);
166 | String url = (String) view.getTag();
167 |
168 | callbacks.onItemClick(venue, view, url);
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/location/GPSTracker.java:
--------------------------------------------------------------------------------
1 | package com.android.test.location;
2 |
3 | import android.app.AlertDialog;
4 | import android.app.Service;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.location.Location;
9 | import android.location.LocationListener;
10 | import android.location.LocationManager;
11 | import android.os.Bundle;
12 | import android.os.IBinder;
13 | import android.provider.Settings;
14 | import android.util.Log;
15 |
16 | import javax.inject.Inject;
17 |
18 |
19 | /**
20 | * Taken from http://stackoverflow.com/questions/19722712/get-user-current-location-android
21 | * Created by nicolas on 12/22/13.
22 | */
23 | public class GPSTracker extends Service implements LocationListener {
24 |
25 | private final Context mContext;
26 |
27 | // flag for GPS status
28 | boolean isGPSEnabled = false;
29 |
30 | // flag for network status
31 | boolean isNetworkEnabled = false;
32 |
33 | // flag for GPS status
34 | boolean canGetLocation = false;
35 |
36 | Location location; // location
37 | double latitude; // latitude
38 | double longitude; // longitude
39 |
40 | // The minimum distance to change Updates in meters
41 | private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
42 |
43 | // The minimum time between updates in milliseconds
44 | private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute
45 |
46 | // Declaring a Location Manager
47 | protected LocationManager locationManager;
48 |
49 | @Inject
50 | public GPSTracker(Context context) {
51 | this.mContext = context;
52 | getLocation();
53 | }
54 |
55 | public Location getLocation() {
56 | try {
57 | locationManager = (LocationManager) mContext
58 | .getSystemService(LOCATION_SERVICE);
59 |
60 | // getting GPS status
61 | isGPSEnabled = locationManager
62 | .isProviderEnabled(LocationManager.GPS_PROVIDER);
63 |
64 | // getting network status
65 | isNetworkEnabled = locationManager
66 | .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
67 |
68 | if (!isGPSEnabled && !isNetworkEnabled) {
69 | // no network provider is enabled
70 | } else {
71 | this.canGetLocation = true;
72 | if (isNetworkEnabled) {
73 | locationManager.requestLocationUpdates(
74 | LocationManager.NETWORK_PROVIDER,
75 | MIN_TIME_BW_UPDATES,
76 | MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
77 | Log.d("Network", "Network");
78 | if (locationManager != null) {
79 | location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
80 | if (location != null) {
81 | latitude = location.getLatitude();
82 | longitude = location.getLongitude();
83 | }
84 | }
85 | }
86 | // if GPS Enabled get lat/long using GPS Services
87 | if (isGPSEnabled) {
88 | if (location == null) {
89 | locationManager.requestLocationUpdates(
90 | LocationManager.GPS_PROVIDER,
91 | MIN_TIME_BW_UPDATES,
92 | MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
93 | Log.d("GPS Enabled", "GPS Enabled");
94 | if (locationManager != null) {
95 | location = locationManager
96 | .getLastKnownLocation(LocationManager.GPS_PROVIDER);
97 | if (location != null) {
98 | latitude = location.getLatitude();
99 | longitude = location.getLongitude();
100 | }
101 | }
102 | }
103 | }
104 | }
105 |
106 | } catch (Exception e) {
107 | e.printStackTrace();
108 | }
109 |
110 | return location;
111 | }
112 |
113 | /**
114 | * Stop using GPS listener
115 | * Calling this function will stop using GPS in your app
116 | * */
117 | public void stopUsingGPS(){
118 | if(locationManager != null){
119 | locationManager.removeUpdates(GPSTracker.this);
120 | }
121 | }
122 |
123 | /**
124 | * Function to get latitude
125 | * */
126 | public double getLatitude(){
127 | if(location != null){
128 | latitude = location.getLatitude();
129 | }
130 |
131 | // return latitude
132 | return latitude;
133 | }
134 |
135 | /**
136 | * Function to get longitude
137 | * */
138 | public double getLongitude(){
139 | if(location != null){
140 | longitude = location.getLongitude();
141 | }
142 |
143 | // return longitude
144 | return longitude;
145 | }
146 |
147 | /**
148 | * Function to check GPS/wifi enabled
149 | * @return boolean
150 | * */
151 | public boolean canGetLocation() {
152 | return this.canGetLocation;
153 | }
154 |
155 | /**
156 | * Function to show settings alert dialog
157 | * On pressing Settings button will lauch Settings Options
158 | * */
159 | public void showSettingsAlert(){
160 | AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
161 |
162 | // Setting Dialog Title
163 | alertDialog.setTitle("GPS is settings");
164 |
165 | // Setting Dialog Message
166 | alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
167 |
168 | // On pressing Settings button
169 | alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
170 | public void onClick(DialogInterface dialog,int which) {
171 | Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
172 | mContext.startActivity(intent);
173 | }
174 | });
175 |
176 | // on pressing cancel button
177 | alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
178 | public void onClick(DialogInterface dialog, int which) {
179 | dialog.cancel();
180 | }
181 | });
182 |
183 | // Showing Alert Message
184 | alertDialog.show();
185 | }
186 |
187 | @Override
188 | public void onLocationChanged(Location location) {
189 | }
190 |
191 | @Override
192 | public void onProviderDisabled(String provider) {
193 | }
194 |
195 | @Override
196 | public void onProviderEnabled(String provider) {
197 | }
198 |
199 | @Override
200 | public void onStatusChanged(String provider, int status, Bundle extras) {
201 | }
202 |
203 | @Override
204 | public IBinder onBind(Intent arg0) {
205 | return null;
206 | }
207 |
208 | }
209 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/module/AndroidDemoModule.java:
--------------------------------------------------------------------------------
1 | package com.android.test.module;
2 |
3 | import android.content.Context;
4 |
5 | import com.android.test.AndroidDemoApplication;
6 | import com.google.inject.AbstractModule;
7 | import com.google.inject.Provider;
8 |
9 | /**
10 | * Created by Nicolas Jafelle on 11/26/14.
11 | */
12 | public class AndroidDemoModule extends AbstractModule {
13 |
14 | @Override
15 | protected void configure() {
16 |
17 | bind(Context.class).toProvider(new Provider() {
18 | @Override
19 | public Context get() {
20 | return AndroidDemoApplication.getAppContext();
21 | }
22 | });
23 | // .in(Singleton.class);
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/otto/OttoBus.java:
--------------------------------------------------------------------------------
1 | package com.android.test.otto;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import com.squareup.otto.Bus;
7 |
8 | import javax.inject.Singleton;
9 |
10 | /**
11 | * Injected Class to use Otto with a Singleton instance and to post always on the main thread.
12 | *
13 | * https://github.com/square/otto/issues/38
14 | */
15 | @Singleton
16 | public class OttoBus extends Bus {
17 |
18 |
19 |
20 | private final Handler mainThread = new Handler(Looper.getMainLooper());
21 |
22 | @Override
23 | public void post(final Object event) {
24 | if (Looper.myLooper() == Looper.getMainLooper()) {
25 | super.post(event);
26 | } else {
27 | mainThread.post(new Runnable() {
28 | @Override
29 | public void run() {
30 | OttoBus.super.post(event);
31 | }
32 | });
33 | }
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/otto/VenueResultEvent.java:
--------------------------------------------------------------------------------
1 | package com.android.test.otto;
2 |
3 | import android.location.Location;
4 |
5 | import com.android.test.domain.Venue;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Created by Nicolas Jafelle on 11/13/14.
11 | */
12 | public class VenueResultEvent {
13 |
14 | public List venues;
15 |
16 | public String place;
17 |
18 | public Location location;
19 |
20 |
21 | public VenueResultEvent(List venues, String place, Location location) {
22 | this.venues = venues;
23 | this.place = place;
24 | this.location = location;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/otto/VenueSearchEvent.java:
--------------------------------------------------------------------------------
1 | package com.android.test.otto;
2 |
3 |
4 | /**
5 | * Created by Nicolas Jafelle on 11/13/14.
6 | */
7 | public class VenueSearchEvent {
8 | public String place;
9 |
10 |
11 | public VenueSearchEvent(String place) {
12 | this.place = place;
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/qachee/QacheeData.java:
--------------------------------------------------------------------------------
1 | package com.android.test.qachee;
2 |
3 | import com.android.test.domain.Venue;
4 | import com.qachee.QacheeableObject;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by Nicolas Jafelle on 11/21/14.
10 | */
11 | public class QacheeData extends QacheeableObject {
12 |
13 | public String search;
14 |
15 | public List venues;
16 |
17 |
18 | public QacheeData(String search, List venues) {
19 | this.search = search;
20 | this.venues = venues;
21 | }
22 |
23 | @Override
24 | public String getKey() {
25 | return search;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/session/SessionManager.java:
--------------------------------------------------------------------------------
1 | package com.android.test.session;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | import com.google.inject.Inject;
7 |
8 | import java.util.HashSet;
9 | import java.util.Set;
10 |
11 | public class SessionManager {
12 |
13 | private SharedPreferences sharedPref;
14 |
15 | private final String PREF_NAME = "android_demo_prefs";
16 | private static final String SAVED_PLACES = "saved_places";
17 |
18 | @Inject
19 | public SessionManager(Context context) {
20 | sharedPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
21 | }
22 |
23 |
24 | public void savePlace(String place) {
25 | Set locations = new HashSet(getSavedPlaces());
26 | locations.add(place);
27 | saveValues(SAVED_PLACES, locations);
28 | }
29 |
30 | public Set getSavedPlaces() {
31 | return this.sharedPref.getStringSet(SAVED_PLACES, new HashSet());
32 | }
33 |
34 | public void clear() {
35 | SharedPreferences.Editor editor = this.sharedPref.edit();
36 | editor.clear();
37 | editor.commit();
38 | }
39 |
40 |
41 | // Helpers
42 | protected void saveValue(String key, String value){
43 | SharedPreferences.Editor editor = this.sharedPref.edit();
44 | editor.putString(key, value);
45 | editor.commit();
46 | }
47 |
48 | protected void saveValues(String key, Set values){
49 | SharedPreferences.Editor editor = this.sharedPref.edit();
50 | editor.putStringSet(key, values);
51 | editor.apply();
52 | }
53 |
54 |
55 |
56 | protected void saveValue(String key, long value){
57 | SharedPreferences.Editor editor = this.sharedPref.edit();
58 | editor.putLong(key,value);
59 | editor.commit();
60 | }
61 |
62 | protected void saveValue(String key, int value){
63 | SharedPreferences.Editor editor = this.sharedPref.edit();
64 | editor.putInt(key, value);
65 | editor.commit();
66 | }
67 |
68 | protected void saveValue(String key, boolean value){
69 | SharedPreferences.Editor editor = this.sharedPref.edit();
70 | editor.putBoolean(key, value);
71 | editor.commit();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/task/FoursquareAsyncTask.java:
--------------------------------------------------------------------------------
1 | package com.android.test.task;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 | import android.widget.Toast;
6 |
7 | import com.android.test.AndroidDemoApplication;
8 | import com.android.test.R;
9 | import com.android.test.dto.FoursquareApiErrorDto;
10 | import com.google.gson.Gson;
11 |
12 | import java.io.BufferedReader;
13 | import java.io.IOException;
14 | import java.io.InputStreamReader;
15 | import java.net.ConnectException;
16 | import java.net.SocketTimeoutException;
17 |
18 | import javax.inject.Inject;
19 |
20 | import retrofit.RetrofitError;
21 |
22 | /**
23 | * Created by nicolas on 12/22/13.
24 | */
25 | public abstract class FoursquareAsyncTask extends SafeAsyncTask {
26 |
27 | @Inject
28 | private Context context;
29 |
30 | protected FoursquareAsyncTask() {
31 | super();
32 | AndroidDemoApplication.injectMembers(this);
33 | }
34 |
35 | @Override
36 | protected void onException(Exception e) throws RuntimeException {
37 | try {
38 | if(e instanceof RetrofitError) {
39 | RetrofitError retrofitError = (RetrofitError) e;
40 | if(retrofitError.getResponse() != null) {
41 | if (retrofitError.getResponse().getStatus() > 500 ){
42 | String msg = "Network error HTTP ("+retrofitError.getResponse().getStatus()+")";
43 | if (retrofitError.getMessage()!=null && !retrofitError.getMessage().isEmpty()){
44 | msg += ": "+retrofitError.getMessage();
45 | }
46 | super.onException(e);
47 | }else if (retrofitError.getBody()==null){
48 | Toast.makeText(this.context, e.getMessage(), Toast.LENGTH_LONG).show();
49 | }else if (retrofitError.getCause() instanceof ConnectException){
50 | Toast.makeText(this.context, R.string.connection_error, Toast.LENGTH_SHORT).show();
51 | }else if (retrofitError.getCause() instanceof SocketTimeoutException){
52 | Toast.makeText(this.context, R.string.connection_error, Toast.LENGTH_SHORT).show();
53 | }else{
54 | BufferedReader reader = new BufferedReader(new InputStreamReader(((RetrofitError) e).getResponse().getBody().in()));
55 | FoursquareApiErrorDto errorDto = new Gson().fromJson(reader, FoursquareApiErrorDto.class);
56 | onApiError(errorDto);
57 | }
58 | }else if(retrofitError.isNetworkError() && !isCancelled()){
59 | Toast.makeText(this.context, R.string.connection_error, Toast.LENGTH_SHORT).show();
60 | }
61 | }else {
62 | super.onException(e);
63 | }
64 | } catch (IOException e1) {
65 | e1.printStackTrace();
66 | }
67 | }
68 |
69 | public void clear() {
70 | this.context = null;
71 | }
72 |
73 | @Override
74 | protected void onInterrupted(Exception e) {
75 | Log.d("BACKGROUND_TASK", "Interrupting background task " + this);
76 | }
77 |
78 | protected abstract void onApiError(FoursquareApiErrorDto errorDto);
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/AndroidDemoApp/App/src/main/java/com/android/test/task/SafeAsyncTask.java:
--------------------------------------------------------------------------------
1 | package com.android.test.task;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.util.Log;
6 |
7 | import java.io.InterruptedIOException;
8 | import java.util.ArrayList;
9 | import java.util.Arrays;
10 | import java.util.concurrent.Callable;
11 | import java.util.concurrent.CountDownLatch;
12 | import java.util.concurrent.Executor;
13 | import java.util.concurrent.Executors;
14 | import java.util.concurrent.FutureTask;
15 |
16 |
17 | /**
18 | * DEPRECATED!!
19 | * A class similar but unrelated to android's {@link android.os.AsyncTask}.
20 | *
21 | * Unlike AsyncTask, this class properly propagates exceptions.
22 | *
23 | * If you're familiar with AsyncTask and are looking for {@link android.os.AsyncTask#doInBackground(Object[])},
24 | * we've named it {@link #call()} here to conform with java 1.5's {@link java.util.concurrent.Callable} interface.
25 | *
26 | * Current limitations: does not yet handle progress, although it shouldn't be
27 | * hard to add.
28 | *
29 | * If using your own executor, you must call future() to get a runnable you can execute.
30 | *
31 | * @param
32 | *
33 | */
34 | public abstract class SafeAsyncTask implements Callable {
35 | public static final int DEFAULT_POOL_SIZE = 25;
36 | protected static final Executor DEFAULT_EXECUTOR = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
37 |
38 | protected Handler handler;
39 | protected Executor executor;
40 | protected StackTraceElement[] launchLocation;
41 | protected FutureTask future;
42 |
43 |
44 | /**
45 | * Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE) and
46 | * Handler to new Handler()
47 | */
48 | public SafeAsyncTask() {
49 | this.executor = DEFAULT_EXECUTOR;
50 | }
51 |
52 | /**
53 | * Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE)
54 | */
55 | public SafeAsyncTask(Handler handler) {
56 | this.handler = handler;
57 | this.executor = DEFAULT_EXECUTOR;
58 | }
59 |
60 | /**
61 | * Sets Handler to new Handler()
62 | */
63 | public SafeAsyncTask(Executor executor) {
64 | this.executor = executor;
65 | }
66 |
67 | public SafeAsyncTask(Handler handler, Executor executor) {
68 | this.handler = handler;
69 | this.executor = executor;
70 | }
71 |
72 |
73 | public FutureTask future() {
74 | future = new FutureTask(newTask());
75 | return future;
76 | }
77 |
78 | public SafeAsyncTask executor(Executor executor) {
79 | this.executor = executor;
80 | return this;
81 | }
82 |
83 | public Executor executor() {
84 | return executor;
85 | }
86 |
87 | public SafeAsyncTask handler(Handler handler) {
88 | this.handler = handler;
89 | return this;
90 | }
91 |
92 | public Handler handler() {
93 | return handler;
94 | }
95 |
96 | public void execute() {
97 | execute(Thread.currentThread().getStackTrace());
98 | }
99 |
100 | protected void execute(StackTraceElement[] launchLocation) {
101 | this.launchLocation = launchLocation;
102 | executor.execute(future());
103 | }
104 |
105 | public boolean cancel(boolean mayInterruptIfRunning) {
106 | if (future == null) throw new UnsupportedOperationException("You cannot cancel this task before calling future()");
107 |
108 | return future.cancel(mayInterruptIfRunning);
109 | }
110 |
111 |
112 | /**
113 | * @throws Exception, captured on passed to onException() if present.
114 | */
115 | protected void onPreExecute() throws Exception {
116 | }
117 |
118 | /**
119 | * @param t the result of {@link #call()}
120 | * @throws Exception, captured on passed to onException() if present.
121 | */
122 | @SuppressWarnings({"UnusedDeclaration"})
123 | protected void onSuccess(ResultT t) throws Exception {
124 | }
125 |
126 | /**
127 | * Called when the thread has been interrupted, likely because
128 | * the task was canceled.
129 | *
130 | * By default, calls {@link #onException(Exception)}, but this method
131 | * may be overridden to handle interruptions differently than other
132 | * exceptions.
133 | *
134 | * @param e an InterruptedException or InterruptedIOException
135 | */
136 | protected void onInterrupted(Exception e) {
137 | onException(e);
138 | }
139 |
140 | /**
141 | * Logs the exception as an Error by default, but this method may
142 | * be overridden by subclasses.
143 | *
144 | * @param e the exception thrown from {@link #onPreExecute()}, {@link #call()}, or {@link #onSuccess(Object)}
145 | * @throws RuntimeException, ignored
146 | */
147 | protected void onException(Exception e) throws RuntimeException {
148 | onThrowable(e);
149 | }
150 |
151 | protected void onThrowable(Throwable t) throws RuntimeException {
152 | Log.e("roboguice", "Throwable caught during background processing", t);
153 | }
154 |
155 | /**
156 | * @throws RuntimeException, ignored
157 | */
158 | protected void onFinally() throws RuntimeException {
159 | }
160 |
161 | public boolean isCancelled(){
162 | return future == null ? false : future.isCancelled();
163 | }
164 |
165 |
166 | protected Task newTask() {
167 | return new Task(this);
168 | }
169 |
170 |
171 | public static class Task implements Callable {
172 | protected SafeAsyncTask parent;
173 | protected Handler handler;
174 |
175 | public Task(SafeAsyncTask parent) {
176 | this.parent = parent;
177 | this.handler = parent.handler != null ? parent.handler : new Handler(Looper.getMainLooper());
178 | }
179 |
180 | public Void call() throws Exception {
181 | try {
182 | doPreExecute();
183 | doSuccess(doCall());
184 |
185 | } catch (final Exception e) {
186 | try {
187 | doException(e);
188 | } catch (Exception f) {
189 | // logged but ignored
190 | Log.e("BACKGROUND_TASK", "Exception in", f);
191 | }
192 |
193 | } catch (final Throwable t) {
194 | try {
195 | doThrowable(t);
196 | } catch (Exception f) {
197 | // logged but ignored
198 | Log.e("BACKGROUND_TASK", "Exception in", f);
199 | }
200 | } finally {
201 | doFinally();
202 | }
203 |
204 | return null;
205 | }
206 |
207 | protected void doPreExecute() throws Exception {
208 | postToUiThreadAndWait(new Callable