4 | Presented by www.AirPair.com
5 | by Rex St. John
6 | www.rexstjohn.com
7 | twitter: @rexstjohn
8 |
9 | The official "Ultimate Android Camera Guide" source repo.
10 |
11 | Includes examples on how to..
12 |
13 |
14 |
Use android's native camera to capture an image
15 |
Use android's external camera to capture an image
16 |
Load images from the gallery into a grid view
17 |
Use Androids gallery to "Select" a single image
18 |
Display images in a horizontal list form
19 |
20 |
21 | INSTRUCTIONS
22 |
23 | Download / clone. Open in Android Studio. Run. The end.
24 |
25 | ATTRIBUTION
26 |
27 | This project makes use of source code snippets provided by Google's Android development portal and TwoWayView by Lucas Rocha: https://github.com/lucasr/twoway-view. Certain code portions are derived partially from results found on StackOverflow during research:
28 |
29 |
32 |
33 | LICENSE
34 |
35 | Copyright (c) 2014 Rex St John, @rexstjohn
36 |
37 | Permission is hereby granted, free of charge, to any person obtaining a copy
38 | of this software and associated documentation files (the "Software"), to deal
39 | in the Software without restriction, including without limitation the rights
40 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41 | copies of the Software, and to permit persons to whom the Software is
42 | furnished to do so, subject to the following conditions:
43 |
44 | The above copyright notice and this permission notice shall be included in
45 | all copies or substantial portions of the Software.
46 |
47 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
52 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53 | THE SOFTWARE.
54 |
--------------------------------------------------------------------------------
/android-camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/android-camera.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:0.9.+'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | mavenCentral()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/camera/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/camera/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion "19.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 11
9 | targetSdkVersion 19
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | debug {
15 | }
16 | release {
17 | runProguard false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
19 | }
20 | }
21 | signingConfigs {
22 | debug {
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | compile 'com.android.support:appcompat-v7:+'
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | }
31 |
--------------------------------------------------------------------------------
/camera/camera.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/camera/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 /Applications/Android Studio.app/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 | #}
--------------------------------------------------------------------------------
/camera/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/camera/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/NavigationDrawerFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera;
24 |
25 | import android.support.v7.app.ActionBarActivity;
26 | import android.app.Activity;
27 | import android.support.v7.app.ActionBar;
28 | import android.support.v4.app.Fragment;
29 | import android.support.v4.app.ActionBarDrawerToggle;
30 | import android.support.v4.view.GravityCompat;
31 | import android.support.v4.widget.DrawerLayout;
32 | import android.content.SharedPreferences;
33 | import android.content.res.Configuration;
34 | import android.os.Bundle;
35 | import android.preference.PreferenceManager;
36 | import android.view.LayoutInflater;
37 | import android.view.Menu;
38 | import android.view.MenuInflater;
39 | import android.view.MenuItem;
40 | import android.view.View;
41 | import android.view.ViewGroup;
42 | import android.widget.AdapterView;
43 | import android.widget.ArrayAdapter;
44 | import android.widget.ListView;
45 | import android.widget.Toast;
46 |
47 | /**
48 | * Fragment used for managing interactions for and presentation of a navigation drawer.
49 | * See the
50 | * design guidelines for a complete explanation of the behaviors implemented here.
51 | */
52 | public class NavigationDrawerFragment extends Fragment {
53 |
54 | /**
55 | * Remember the position of the selected item.
56 | */
57 | private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
58 |
59 | /**
60 | * Per the design guidelines, you should show the drawer on launch until the user manually
61 | * expands it. This shared preference tracks this.
62 | */
63 | private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
64 |
65 | /**
66 | * A pointer to the current callbacks instance (the Activity).
67 | */
68 | private NavigationDrawerCallbacks mCallbacks;
69 |
70 | /**
71 | * Helper component that ties the action bar to the navigation drawer.
72 | */
73 | private ActionBarDrawerToggle mDrawerToggle;
74 |
75 | private DrawerLayout mDrawerLayout;
76 | private ListView mDrawerListView;
77 | private View mFragmentContainerView;
78 |
79 | private int mCurrentSelectedPosition = 0;
80 | private boolean mFromSavedInstanceState;
81 | private boolean mUserLearnedDrawer;
82 |
83 | public NavigationDrawerFragment() {
84 | }
85 |
86 | @Override
87 | public void onCreate(Bundle savedInstanceState) {
88 | super.onCreate(savedInstanceState);
89 |
90 | // Read in the flag indicating whether or not the user has demonstrated awareness of the
91 | // drawer. See PREF_USER_LEARNED_DRAWER for details.
92 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
93 | mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
94 |
95 | if (savedInstanceState != null) {
96 | mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
97 | mFromSavedInstanceState = true;
98 | }
99 |
100 | // Select either the default item (0) or the last selected item.
101 | selectItem(mCurrentSelectedPosition);
102 | }
103 |
104 | @Override
105 | public void onActivityCreated (Bundle savedInstanceState) {
106 | super.onActivityCreated(savedInstanceState);
107 | // Indicate that this fragment would like to influence the set of actions in the action bar.
108 | setHasOptionsMenu(true);
109 | }
110 |
111 | @Override
112 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
113 | Bundle savedInstanceState) {
114 | mDrawerListView = (ListView) inflater.inflate(
115 | R.layout.fragment_navigation_drawer, container, false);
116 | mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
117 | @Override
118 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
119 | selectItem(position);
120 | }
121 | });
122 | mDrawerListView.setAdapter(new ArrayAdapter(
123 | getActionBar().getThemedContext(),
124 | android.R.layout.simple_list_item_activated_1,
125 | android.R.id.text1,
126 | new String[]{
127 | getString(R.string.title_section1),
128 | getString(R.string.title_section2),
129 | getString(R.string.title_section3),
130 | getString(R.string.title_section4),
131 | getString(R.string.title_section5)
132 | }));
133 | mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
134 | return mDrawerListView;
135 | }
136 |
137 | public boolean isDrawerOpen() {
138 | return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
139 | }
140 |
141 | /**
142 | * Users of this fragment must call this method to set up the navigation drawer interactions.
143 | *
144 | * @param fragmentId The android:id of this fragment in its activity's layout.
145 | * @param drawerLayout The DrawerLayout containing this fragment's UI.
146 | */
147 | public void setUp(int fragmentId, DrawerLayout drawerLayout) {
148 | mFragmentContainerView = getActivity().findViewById(fragmentId);
149 | mDrawerLayout = drawerLayout;
150 |
151 | // set a custom shadow that overlays the main content when the drawer opens
152 | mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
153 | // set up the drawer's list view with items and click listener
154 |
155 | ActionBar actionBar = getActionBar();
156 | actionBar.setDisplayHomeAsUpEnabled(true);
157 | actionBar.setHomeButtonEnabled(true);
158 |
159 | // ActionBarDrawerToggle ties together the the proper interactions
160 | // between the navigation drawer and the action bar app icon.
161 | mDrawerToggle = new ActionBarDrawerToggle(
162 | getActivity(), /* host Activity */
163 | mDrawerLayout, /* DrawerLayout object */
164 | R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
165 | R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
166 | R.string.navigation_drawer_close /* "close drawer" description for accessibility */
167 | ) {
168 | @Override
169 | public void onDrawerClosed(View drawerView) {
170 | super.onDrawerClosed(drawerView);
171 | if (!isAdded()) {
172 | return;
173 | }
174 |
175 | getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
176 | }
177 |
178 | @Override
179 | public void onDrawerOpened(View drawerView) {
180 | super.onDrawerOpened(drawerView);
181 | if (!isAdded()) {
182 | return;
183 | }
184 |
185 | if (!mUserLearnedDrawer) {
186 | // The user manually opened the drawer; store this flag to prevent auto-showing
187 | // the navigation drawer automatically in the future.
188 | mUserLearnedDrawer = true;
189 | SharedPreferences sp = PreferenceManager
190 | .getDefaultSharedPreferences(getActivity());
191 | sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
192 | }
193 |
194 | getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
195 | }
196 | };
197 |
198 | // If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
199 | // per the navigation drawer design guidelines.
200 | if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
201 | mDrawerLayout.openDrawer(mFragmentContainerView);
202 | }
203 |
204 | // Defer code dependent on restoration of previous instance state.
205 | mDrawerLayout.post(new Runnable() {
206 | @Override
207 | public void run() {
208 | mDrawerToggle.syncState();
209 | }
210 | });
211 |
212 | mDrawerLayout.setDrawerListener(mDrawerToggle);
213 | }
214 |
215 | private void selectItem(int position) {
216 | mCurrentSelectedPosition = position;
217 | if (mDrawerListView != null) {
218 | mDrawerListView.setItemChecked(position, true);
219 | }
220 | if (mDrawerLayout != null) {
221 | mDrawerLayout.closeDrawer(mFragmentContainerView);
222 | }
223 | if (mCallbacks != null) {
224 | mCallbacks.onNavigationDrawerItemSelected(position);
225 | }
226 | }
227 |
228 | @Override
229 | public void onAttach(Activity activity) {
230 | super.onAttach(activity);
231 | try {
232 | mCallbacks = (NavigationDrawerCallbacks) activity;
233 | } catch (ClassCastException e) {
234 | throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
235 | }
236 | }
237 |
238 | @Override
239 | public void onDetach() {
240 | super.onDetach();
241 | mCallbacks = null;
242 | }
243 |
244 | @Override
245 | public void onSaveInstanceState(Bundle outState) {
246 | super.onSaveInstanceState(outState);
247 | outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
248 | }
249 |
250 | @Override
251 | public void onConfigurationChanged(Configuration newConfig) {
252 | super.onConfigurationChanged(newConfig);
253 | // Forward the new configuration the drawer toggle component.
254 | mDrawerToggle.onConfigurationChanged(newConfig);
255 | }
256 |
257 | @Override
258 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
259 | // If the drawer is open, show the global app actions in the action bar. See also
260 | // showGlobalContextActionBar, which controls the top-left area of the action bar.
261 | if (mDrawerLayout != null && isDrawerOpen()) {
262 | inflater.inflate(R.menu.global, menu);
263 | showGlobalContextActionBar();
264 | }
265 | super.onCreateOptionsMenu(menu, inflater);
266 | }
267 |
268 | @Override
269 | public boolean onOptionsItemSelected(MenuItem item) {
270 | if (mDrawerToggle.onOptionsItemSelected(item)) {
271 | return true;
272 | }
273 |
274 | return super.onOptionsItemSelected(item);
275 | }
276 |
277 | /**
278 | * Per the navigation drawer design guidelines, updates the action bar to show the global app
279 | * 'context', rather than just what's in the current screen.
280 | */
281 | private void showGlobalContextActionBar() {
282 | ActionBar actionBar = getActionBar();
283 | actionBar.setDisplayShowTitleEnabled(true);
284 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
285 | actionBar.setTitle(R.string.app_name);
286 | }
287 |
288 | private ActionBar getActionBar() {
289 | return ((ActionBarActivity) getActivity()).getSupportActionBar();
290 | }
291 |
292 | /**
293 | * Callbacks interface that all activities using this fragment must implement.
294 | */
295 | public static interface NavigationDrawerCallbacks {
296 | /**
297 | * Called when an item in the navigation drawer is selected.
298 | */
299 | void onNavigationDrawerItemSelected(int position);
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/activities/CameraActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.activities;
24 |
25 | import android.net.Uri;
26 | import android.os.Bundle;
27 | import android.support.v7.app.ActionBarActivity;
28 |
29 | /**
30 | * This activity assists in trapping the camera's "State" e.g. where the camera plans
31 | * on saving it's resulting file and URI. This activity saves this information to the bundle
32 | * and retrieves it on resume. This is necessary because when the Android external camera starts,
33 | * the file path anf URI get collected and won't be available on resume, resulting in a crash.
34 | *
35 | * Samsung devices, in particular may crash if you don't do this:
36 | * Reference: http://stackoverflow.com/questions/8248327/my-android-camera-uri-is-returning-a-null-value-but-the-samsung-fix-is-in-place
37 | *
38 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
39 | */
40 | public class CameraActivity extends ActionBarActivity {
41 |
42 | // Storage for camera image URI components
43 | private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";
44 | private final static String CAPTURED_PHOTO_URI_KEY = "mCapturedImageURI";
45 |
46 | // Required for camera operations in order to save the image file on resume.
47 | private String mCurrentPhotoPath = null;
48 | private Uri mCapturedImageURI = null;
49 |
50 | @Override
51 | public void onSaveInstanceState(Bundle savedInstanceState) {
52 | if (mCurrentPhotoPath != null) {
53 | savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath);
54 | }
55 | if (mCapturedImageURI != null) {
56 | savedInstanceState.putString(CAPTURED_PHOTO_URI_KEY, mCapturedImageURI.toString());
57 | }
58 | super.onSaveInstanceState(savedInstanceState);
59 | }
60 |
61 | @Override
62 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
63 | if (savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
64 | mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY);
65 | }
66 | if (savedInstanceState.containsKey(CAPTURED_PHOTO_URI_KEY)) {
67 | mCapturedImageURI = Uri.parse(savedInstanceState.getString(CAPTURED_PHOTO_URI_KEY));
68 | }
69 | super.onRestoreInstanceState(savedInstanceState);
70 | }
71 |
72 | /**
73 | * Getters and setters.
74 | */
75 |
76 | public String getCurrentPhotoPath() {
77 | return mCurrentPhotoPath;
78 | }
79 |
80 | public void setCurrentPhotoPath(String mCurrentPhotoPath) {
81 | this.mCurrentPhotoPath = mCurrentPhotoPath;
82 | }
83 |
84 | public Uri getCapturedImageURI() {
85 | return mCapturedImageURI;
86 | }
87 |
88 | public void setCapturedImageURI(Uri mCapturedImageURI) {
89 | this.mCapturedImageURI = mCapturedImageURI;
90 | }
91 | }
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.activities;
24 |
25 | import android.app.FragmentManager;
26 | import android.net.Uri;
27 | import android.os.Bundle;
28 | import android.support.v4.widget.DrawerLayout;
29 | import android.support.v7.app.ActionBar;
30 | import android.view.Menu;
31 | import android.view.MenuItem;
32 |
33 | import com.ultimate.camera.NavigationDrawerFragment;
34 | import com.ultimate.camera.R;
35 | import com.ultimate.camera.fragments.BaseFragment;
36 | import com.ultimate.camera.fragments.HorizontalPhotoGalleryFragment;
37 | import com.ultimate.camera.fragments.NativeCameraFragment;
38 | import com.ultimate.camera.fragments.SimpleAndroidImagePickerFragment;
39 | import com.ultimate.camera.fragments.SimpleCameraIntentFragment;
40 | import com.ultimate.camera.fragments.SimplePhotoGalleryListFragment;
41 |
42 | /**
43 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
44 | */
45 | public class MainActivity extends CameraActivity
46 | implements NavigationDrawerFragment.NavigationDrawerCallbacks, BaseFragment.OnFragmentInteractionListener {
47 |
48 | /**
49 | * Actions
50 | */
51 | public static final int SELECT_PHOTO_ACTION = 0;
52 |
53 | /**
54 | * Fragment Identifiers
55 | */
56 | public static final int SIMPLE_CAMERA_INTENT_FRAGMENT = 0;
57 | public static final int SIMPLE_PHOTO_GALLERY_FRAGMENT = 1;
58 | public static final int SIMPLE_PHOTO_PICKER_FRAGMENT = 2;
59 | public static final int NATIVE_CAMERA_FRAGMENT = 3;
60 | public static final int HORIZONTAL_GALLERY_FRAGMENT = 4;
61 |
62 | /**
63 | * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
64 | */
65 | private NavigationDrawerFragment mNavigationDrawerFragment;
66 |
67 | /**
68 | * Used to store the last screen title. For use in {@link #restoreActionBar()}.
69 | */
70 | private CharSequence mTitle;
71 |
72 | @Override
73 | protected void onCreate(Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | setContentView(R.layout.activity_main);
76 |
77 | mNavigationDrawerFragment = (NavigationDrawerFragment)
78 | getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
79 | mTitle = getTitle();
80 |
81 | // Set up the drawer.
82 | mNavigationDrawerFragment.setUp(
83 | R.id.navigation_drawer,
84 | (DrawerLayout) findViewById(R.id.drawer_layout));
85 | }
86 |
87 | @Override
88 | public void onNavigationDrawerItemSelected(int position) {
89 |
90 | // update the main content by replacing fragments
91 | FragmentManager fragmentManager = getFragmentManager();
92 | BaseFragment targetFragment = null;
93 |
94 | // Populate the fragment
95 | switch (position) {
96 | case SIMPLE_CAMERA_INTENT_FRAGMENT: {
97 | targetFragment = SimpleCameraIntentFragment.newInstance(position + 1);
98 | break;
99 | }
100 | case SIMPLE_PHOTO_GALLERY_FRAGMENT: {
101 | targetFragment = SimplePhotoGalleryListFragment.newInstance(position + 1);
102 | break;
103 | }
104 | case SIMPLE_PHOTO_PICKER_FRAGMENT: {
105 | targetFragment = SimpleAndroidImagePickerFragment.newInstance(position + 1);
106 | break;
107 | }
108 | case NATIVE_CAMERA_FRAGMENT: {
109 | targetFragment = NativeCameraFragment.newInstance(position + 1);
110 | break;
111 | }
112 | case HORIZONTAL_GALLERY_FRAGMENT:{
113 | targetFragment = HorizontalPhotoGalleryFragment.newInstance(position + 1);
114 | break;
115 | }
116 | default:
117 | break;
118 | }
119 |
120 | // Select the fragment.
121 | fragmentManager.beginTransaction()
122 | .replace(R.id.container, targetFragment)
123 | .commit();
124 | }
125 |
126 | public void onSectionAttached(int number) {
127 | switch (number) {
128 | case 1:
129 | mTitle = getString(R.string.title_section1);
130 | break;
131 | case 2:
132 | mTitle = getString(R.string.title_section2);
133 | break;
134 | case 3:
135 | mTitle = getString(R.string.title_section3);
136 | break;
137 | case 4:
138 | mTitle = getString(R.string.title_section4);
139 | break;
140 | case 5:
141 | mTitle = getString(R.string.title_section5);
142 | break;
143 | }
144 | }
145 |
146 | public void restoreActionBar() {
147 | ActionBar actionBar = getSupportActionBar();
148 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
149 | actionBar.setDisplayShowTitleEnabled(true);
150 | actionBar.setTitle(mTitle);
151 | }
152 |
153 | @Override
154 | public boolean onCreateOptionsMenu(Menu menu) {
155 | if (!mNavigationDrawerFragment.isDrawerOpen()) {
156 | // Only show items in the action bar relevant to this screen
157 | // if the drawer is not showing. Otherwise, let the drawer
158 | // decide what to show in the action bar.
159 | getMenuInflater().inflate(R.menu.main, menu);
160 | restoreActionBar();
161 | return true;
162 | }
163 | return super.onCreateOptionsMenu(menu);
164 | }
165 |
166 | @Override
167 | public boolean onOptionsItemSelected(MenuItem item) {
168 | // Handle action bar item clicks here. The action bar will
169 | // automatically handle clicks on the Home/Up button, so long
170 | // as you specify a parent activity in AndroidManifest.xml.
171 | int id = item.getItemId();
172 | return super.onOptionsItemSelected(item);
173 | }
174 |
175 | /**
176 | * Handle Incoming messages from contained fragments.
177 | */
178 |
179 | @Override
180 | public void onFragmentInteraction(Uri uri) {
181 |
182 | }
183 |
184 | @Override
185 | public void onFragmentInteraction(String id) {
186 |
187 | }
188 |
189 | @Override
190 | public void onFragmentInteraction(int actionId) {
191 |
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/adapters/PhotoAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.adapters;
24 |
25 | import android.app.Activity;
26 | import android.content.Context;
27 | import android.view.LayoutInflater;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 | import android.widget.ArrayAdapter;
31 | import android.widget.CheckBox;
32 | import android.widget.CompoundButton;
33 | import android.widget.ImageView;
34 |
35 | import com.ultimate.camera.R;
36 | import com.ultimate.camera.adapters.items.PhotoItem;
37 |
38 | import java.util.List;
39 |
40 | /**
41 | * Photo Array Adapter to power a simple Android photo gallery.
42 | *
43 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
44 | */
45 | public class PhotoAdapter extends ArrayAdapter{
46 |
47 | // Ivars.
48 | private Context context;
49 | private int resourceId;
50 |
51 | public PhotoAdapter(Context context, int resourceId,
52 | List items, boolean useList) {
53 | super(context, resourceId, items);
54 | this.context = context;
55 | this.resourceId = resourceId;
56 | }
57 |
58 | /**
59 | * The "ViewHolder" pattern is used for speed.
60 | *
61 | * Reference: http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html
62 | */
63 | private class ViewHolder {
64 | ImageView photoImageView;
65 | }
66 |
67 | /**
68 | * Populate the view holder with data.
69 | * @param position
70 | * @param convertView
71 | * @param parent
72 | * @return
73 | */
74 | public View getView(int position, View convertView, ViewGroup parent) {
75 | ViewHolder holder = null;
76 | PhotoItem photoItem = getItem(position);
77 | View viewToUse = null;
78 |
79 | // This block exists to inflate the photo list item conditionally based on whether
80 | // we want to support a grid or list view.
81 | LayoutInflater mInflater = (LayoutInflater) context
82 | .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
83 | if (convertView == null) {
84 | holder = new ViewHolder();
85 | viewToUse = mInflater.inflate(resourceId, null);
86 | holder.photoImageView = (ImageView) viewToUse.findViewById(R.id.imageView);
87 | viewToUse.setTag(holder);
88 | } else {
89 | viewToUse = convertView;
90 | holder = (ViewHolder) viewToUse.getTag();
91 | }
92 |
93 | // Set the thumbnail
94 | holder.photoImageView.setImageURI(photoItem.getThumbnailUri());
95 |
96 | return viewToUse;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/adapters/items/PhotoItem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.adapters.items;
24 |
25 | import android.net.Uri;
26 |
27 | /**
28 | * Used to represent a photo item.
29 | *
30 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
31 | */
32 | public class PhotoItem {
33 |
34 | // Ivars.
35 | private Uri thumbnailUri;
36 | private Uri fullImageUri;
37 |
38 | public PhotoItem(Uri thumbnailUri,Uri fullImageUri) {
39 | this.thumbnailUri = thumbnailUri;
40 | this.fullImageUri = fullImageUri;
41 | }
42 |
43 | /**
44 | * Getters and setters
45 | */
46 | public Uri getThumbnailUri() {
47 | return thumbnailUri;
48 | }
49 |
50 | public void setThumbnailUri(Uri thumbnailUri) {
51 | this.thumbnailUri = thumbnailUri;
52 | }
53 |
54 | public Uri getFullImageUri() {
55 | return fullImageUri;
56 | }
57 |
58 | public void setFullImageUri(Uri fullImageUri) {
59 | this.fullImageUri = fullImageUri;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/fragments/BaseFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.fragments;
24 |
25 | import android.app.Fragment;
26 | import android.net.Uri;
27 | import android.os.Bundle;
28 |
29 | /**
30 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
31 | */
32 | public class BaseFragment extends Fragment {
33 |
34 | public static final String ARG_SECTION_NUMBER = "ARG_SECTION_NUMBER";
35 |
36 | /**
37 | * Default empty constructor
38 | */
39 | public BaseFragment(){
40 | //
41 | }
42 |
43 | /**
44 | * This interface must be implemented by activities that contain this
45 | * mFragment to allow an interaction in this mFragment to be communicated
46 | * to the mActivity and potentially other fragments contained in that
47 | * mActivity.
48 | *
49 | * See the Android Training lesson Communicating with Other Fragments for more information.
52 | */
53 | public interface OnFragmentInteractionListener {
54 | public void onFragmentInteraction(Uri uri);
55 | public void onFragmentInteraction(String id);
56 | public void onFragmentInteraction(int actionId);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/fragments/HorizontalPhotoGalleryFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.fragments;
24 |
25 | import android.os.Bundle;
26 | import android.view.LayoutInflater;
27 | import android.view.View;
28 | import android.view.ViewGroup;
29 | import android.widget.AbsListView;
30 | import android.widget.AdapterView;
31 | import android.widget.ListAdapter;
32 | import android.widget.TextView;
33 |
34 | import com.ultimate.camera.R;
35 | import com.ultimate.camera.views.TwoWayView;
36 |
37 | /**
38 | * A demonstration of showing images in a horizontal image gallery.
39 | *
40 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
41 | */
42 | public class HorizontalPhotoGalleryFragment extends SimplePhotoGalleryListFragment {
43 |
44 | // Left and right scrolling two way view
45 | private TwoWayView mHorizontalListView;
46 |
47 | public HorizontalPhotoGalleryFragment(){
48 | super();
49 | }
50 |
51 | /**
52 | * Static factory method
53 | * @param sectionNumber
54 | * @return
55 | */
56 | public static HorizontalPhotoGalleryFragment newInstance(int sectionNumber) {
57 | HorizontalPhotoGalleryFragment fragment = new HorizontalPhotoGalleryFragment();
58 | Bundle args = new Bundle();
59 | args.putInt(ARG_SECTION_NUMBER, sectionNumber);
60 | fragment.setArguments(args);
61 | return fragment;
62 | }
63 |
64 | /**
65 | * Create View!
66 | * @param inflater
67 | * @param container
68 | * @param savedInstanceState
69 | * @return
70 | */
71 | @Override
72 | public View onCreateView(LayoutInflater inflater,
73 | ViewGroup container,
74 | Bundle savedInstanceState) {
75 | View view = null;
76 | view = inflater.inflate(R.layout.fragment_horizontal_gallery, container, false);
77 |
78 | // Set the mAdapter
79 | mEmptyTextView = (TextView)view.findViewById(R.id.empty);
80 | mHorizontalListView = (TwoWayView) view.findViewById(R.id.horizontalList);
81 | mHorizontalListView.setAdapter(mAdapter);
82 | mHorizontalListView.setItemMargin(10);
83 |
84 | resolveEmptyText();
85 |
86 | return view;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/fragments/NativeCameraFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.fragments;
24 |
25 | import android.content.Context;
26 | import android.hardware.Camera;
27 | import android.os.Bundle;
28 | import android.os.Environment;
29 | import android.util.Log;
30 | import android.view.Display;
31 | import android.view.LayoutInflater;
32 | import android.view.Surface;
33 | import android.view.SurfaceHolder;
34 | import android.view.SurfaceView;
35 | import android.view.View;
36 | import android.view.ViewGroup;
37 | import android.view.WindowManager;
38 | import android.widget.Button;
39 | import android.widget.FrameLayout;
40 | import android.widget.ImageView;
41 | import android.widget.Toast;
42 |
43 | import com.ultimate.camera.R;
44 | import com.ultimate.camera.utilities.DialogHelper;
45 |
46 | import java.io.File;
47 | import java.io.FileNotFoundException;
48 | import java.io.FileOutputStream;
49 | import java.io.IOException;
50 | import java.text.SimpleDateFormat;
51 | import java.util.Date;
52 | import java.util.List;
53 |
54 | /**
55 | * Take a picture directly from inside the app using this fragment.
56 | *
57 | * Reference: http://developer.android.com/training/camera/cameradirect.html
58 | * Reference: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
59 | * Reference: http://stackoverflow.com/questions/10913181/camera-preview-is-not-restarting
60 | *
61 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
62 | */
63 | public class NativeCameraFragment extends BaseFragment {
64 |
65 | // Native camera.
66 | private Camera mCamera;
67 |
68 | // View to display the camera output.
69 | private CameraPreview mPreview;
70 |
71 | // Reference to the containing view.
72 | private View mCameraView;
73 |
74 | /**
75 | * Default empty constructor.
76 | */
77 | public NativeCameraFragment(){
78 | super();
79 | }
80 |
81 | /**
82 | * Static factory method
83 | * @param sectionNumber
84 | * @return
85 | */
86 | public static NativeCameraFragment newInstance(int sectionNumber) {
87 | NativeCameraFragment fragment = new NativeCameraFragment();
88 | Bundle args = new Bundle();
89 | args.putInt(ARG_SECTION_NUMBER, sectionNumber);
90 | fragment.setArguments(args);
91 | return fragment;
92 | }
93 |
94 | /**
95 | * OnCreateView fragment override
96 | * @param inflater
97 | * @param container
98 | * @param savedInstanceState
99 | * @return
100 | */
101 | @Override
102 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
103 | Bundle savedInstanceState) {
104 | View view = inflater.inflate(R.layout.fragment_native_camera, container, false);
105 |
106 | // Create our Preview view and set it as the content of our activity.
107 | boolean opened = safeCameraOpenInView(view);
108 |
109 | if(opened == false){
110 | Log.d("CameraGuide","Error, Camera failed to open");
111 | return view;
112 | }
113 |
114 | // Trap the capture button.
115 | Button captureButton = (Button) view.findViewById(R.id.button_capture);
116 | captureButton.setOnClickListener(
117 | new View.OnClickListener() {
118 | @Override
119 | public void onClick(View v) {
120 | // get an image from the camera
121 | mCamera.takePicture(null, null, mPicture);
122 | }
123 | }
124 | );
125 |
126 | return view;
127 | }
128 |
129 | /**
130 | * Recommended "safe" way to open the camera.
131 | * @param view
132 | * @return
133 | */
134 | private boolean safeCameraOpenInView(View view) {
135 | boolean qOpened = false;
136 | releaseCameraAndPreview();
137 | mCamera = getCameraInstance();
138 | mCameraView = view;
139 | qOpened = (mCamera != null);
140 |
141 | if(qOpened == true){
142 | mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera,view);
143 | FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview);
144 | preview.addView(mPreview);
145 | mPreview.startCameraPreview();
146 | }
147 | return qOpened;
148 | }
149 |
150 | /**
151 | * Safe method for getting a camera instance.
152 | * @return
153 | */
154 | public static Camera getCameraInstance(){
155 | Camera c = null;
156 | try {
157 | c = Camera.open(); // attempt to get a Camera instance
158 | }
159 | catch (Exception e){
160 | e.printStackTrace();
161 | }
162 | return c; // returns null if camera is unavailable
163 | }
164 |
165 | @Override
166 | public void onPause() {
167 | super.onPause();
168 | }
169 |
170 | @Override
171 | public void onDestroy() {
172 | super.onDestroy();
173 | releaseCameraAndPreview();
174 | }
175 |
176 | /**
177 | * Clear any existing preview / camera.
178 | */
179 | private void releaseCameraAndPreview() {
180 |
181 | if (mCamera != null) {
182 | mCamera.stopPreview();
183 | mCamera.release();
184 | mCamera = null;
185 | }
186 | if(mPreview != null){
187 | mPreview.destroyDrawingCache();
188 | mPreview.mCamera = null;
189 | }
190 | }
191 |
192 | /**
193 | * Surface on which the camera projects it's capture results. This is derived both from Google's docs and the
194 | * excellent StackOverflow answer provided below.
195 | *
196 | * Reference / Credit: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
197 | */
198 | class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
199 |
200 | // SurfaceHolder
201 | private SurfaceHolder mHolder;
202 |
203 | // Our Camera.
204 | private Camera mCamera;
205 |
206 | // Parent Context.
207 | private Context mContext;
208 |
209 | // Camera Sizing (For rotation, orientation changes)
210 | private Camera.Size mPreviewSize;
211 |
212 | // List of supported preview sizes
213 | private List mSupportedPreviewSizes;
214 |
215 | // Flash modes supported by this camera
216 | private List mSupportedFlashModes;
217 |
218 | // View holding this camera.
219 | private View mCameraView;
220 |
221 | public CameraPreview(Context context, Camera camera, View cameraView) {
222 | super(context);
223 |
224 | // Capture the context
225 | mCameraView = cameraView;
226 | mContext = context;
227 | setCamera(camera);
228 |
229 | // Install a SurfaceHolder.Callback so we get notified when the
230 | // underlying surface is created and destroyed.
231 | mHolder = getHolder();
232 | mHolder.addCallback(this);
233 | mHolder.setKeepScreenOn(true);
234 | // deprecated setting, but required on Android versions prior to 3.0
235 | mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
236 | }
237 |
238 | /**
239 | * Begin the preview of the camera input.
240 | */
241 | public void startCameraPreview()
242 | {
243 | try{
244 | mCamera.setPreviewDisplay(mHolder);
245 | mCamera.startPreview();
246 | }
247 | catch(Exception e){
248 | e.printStackTrace();
249 | }
250 | }
251 |
252 | /**
253 | * Extract supported preview and flash modes from the camera.
254 | * @param camera
255 | */
256 | private void setCamera(Camera camera)
257 | {
258 | // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
259 | mCamera = camera;
260 | mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
261 | mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
262 |
263 | // Set the camera to Auto Flash mode.
264 | if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
265 | Camera.Parameters parameters = mCamera.getParameters();
266 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
267 | mCamera.setParameters(parameters);
268 | }
269 |
270 | requestLayout();
271 | }
272 |
273 | /**
274 | * The Surface has been created, now tell the camera where to draw the preview.
275 | * @param holder
276 | */
277 | public void surfaceCreated(SurfaceHolder holder) {
278 | try {
279 | mCamera.setPreviewDisplay(holder);
280 | } catch (IOException e) {
281 | e.printStackTrace();
282 | }
283 | }
284 |
285 | /**
286 | * Dispose of the camera preview.
287 | * @param holder
288 | */
289 | public void surfaceDestroyed(SurfaceHolder holder) {
290 | if (mCamera != null){
291 | mCamera.stopPreview();
292 | }
293 | }
294 |
295 | /**
296 | * React to surface changed events
297 | * @param holder
298 | * @param format
299 | * @param w
300 | * @param h
301 | */
302 | public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
303 | // If your preview can change or rotate, take care of those events here.
304 | // Make sure to stop the preview before resizing or reformatting it.
305 |
306 | if (mHolder.getSurface() == null){
307 | // preview surface does not exist
308 | return;
309 | }
310 |
311 | // stop preview before making changes
312 | try {
313 | Camera.Parameters parameters = mCamera.getParameters();
314 |
315 | // Set the auto-focus mode to "continuous"
316 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
317 |
318 | // Preview size must exist.
319 | if(mPreviewSize != null) {
320 | Camera.Size previewSize = mPreviewSize;
321 | parameters.setPreviewSize(previewSize.width, previewSize.height);
322 | }
323 |
324 | mCamera.setParameters(parameters);
325 | mCamera.startPreview();
326 | } catch (Exception e){
327 | e.printStackTrace();
328 | }
329 | }
330 |
331 | /**
332 | * Calculate the measurements of the layout
333 | * @param widthMeasureSpec
334 | * @param heightMeasureSpec
335 | */
336 | @Override
337 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
338 | {
339 | // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
340 | final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
341 | final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
342 | setMeasuredDimension(width, height);
343 |
344 | if (mSupportedPreviewSizes != null){
345 | mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
346 | }
347 | }
348 |
349 | /**
350 | * Update the layout based on rotation and orientation changes.
351 | * @param changed
352 | * @param left
353 | * @param top
354 | * @param right
355 | * @param bottom
356 | */
357 | @Override
358 | protected void onLayout(boolean changed, int left, int top, int right, int bottom)
359 | {
360 | // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
361 | if (changed) {
362 | final int width = right - left;
363 | final int height = bottom - top;
364 |
365 | int previewWidth = width;
366 | int previewHeight = height;
367 |
368 | if (mPreviewSize != null){
369 | Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
370 |
371 | switch (display.getRotation())
372 | {
373 | case Surface.ROTATION_0:
374 | previewWidth = mPreviewSize.height;
375 | previewHeight = mPreviewSize.width;
376 | mCamera.setDisplayOrientation(90);
377 | break;
378 | case Surface.ROTATION_90:
379 | previewWidth = mPreviewSize.width;
380 | previewHeight = mPreviewSize.height;
381 | break;
382 | case Surface.ROTATION_180:
383 | previewWidth = mPreviewSize.height;
384 | previewHeight = mPreviewSize.width;
385 | break;
386 | case Surface.ROTATION_270:
387 | previewWidth = mPreviewSize.width;
388 | previewHeight = mPreviewSize.height;
389 | mCamera.setDisplayOrientation(180);
390 | break;
391 | }
392 | }
393 |
394 | final int scaledChildHeight = previewHeight * width / previewWidth;
395 | mCameraView.layout(0, height - scaledChildHeight, width, height);
396 | }
397 | }
398 |
399 | /**
400 | *
401 | * @param sizes
402 | * @param width
403 | * @param height
404 | * @return
405 | */
406 | private Camera.Size getOptimalPreviewSize(List sizes, int width, int height)
407 | {
408 | // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
409 | Camera.Size optimalSize = null;
410 |
411 | final double ASPECT_TOLERANCE = 0.1;
412 | double targetRatio = (double) height / width;
413 |
414 | // Try to find a size match which suits the whole screen minus the menu on the left.
415 | for (Camera.Size size : sizes){
416 |
417 | if (size.height != width) continue;
418 | double ratio = (double) size.width / size.height;
419 | if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE){
420 | optimalSize = size;
421 | }
422 | }
423 |
424 | // If we cannot find the one that matches the aspect ratio, ignore the requirement.
425 | if (optimalSize == null) {
426 | // TODO : Backup in case we don't get a size.
427 | }
428 |
429 | return optimalSize;
430 | }
431 | }
432 |
433 | /**
434 | * Picture Callback for handling a picture capture and saving it out to a file.
435 | */
436 | private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
437 |
438 | @Override
439 | public void onPictureTaken(byte[] data, Camera camera) {
440 |
441 | File pictureFile = getOutputMediaFile();
442 | if (pictureFile == null){
443 | Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT)
444 | .show();
445 | return;
446 | }
447 |
448 | try {
449 | FileOutputStream fos = new FileOutputStream(pictureFile);
450 | fos.write(data);
451 | fos.close();
452 |
453 | // Restart the camera preview.
454 | safeCameraOpenInView(mCameraView);
455 | } catch (FileNotFoundException e) {
456 | e.printStackTrace();
457 | } catch (IOException e) {
458 | e.printStackTrace();
459 | }
460 | }
461 | };
462 |
463 | /**
464 | * Used to return the camera File output.
465 | * @return
466 | */
467 | private File getOutputMediaFile(){
468 |
469 | File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
470 | Environment.DIRECTORY_PICTURES), "UltimateCameraGuideApp");
471 |
472 | if (! mediaStorageDir.exists()){
473 | if (! mediaStorageDir.mkdirs()){
474 | Log.d("Camera Guide", "Required media storage does not exist");
475 | return null;
476 | }
477 | }
478 |
479 | // Create a media file name
480 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
481 | File mediaFile;
482 | mediaFile = new File(mediaStorageDir.getPath() + File.separator +
483 | "IMG_"+ timeStamp + ".jpg");
484 |
485 | DialogHelper.showDialog( "Success!","Your picture has been saved!",getActivity());
486 |
487 | return mediaFile;
488 | }
489 | }
490 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/fragments/SimpleAndroidImagePickerFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.fragments;
24 |
25 | import android.app.Activity;
26 | import android.content.Context;
27 | import android.content.Intent;
28 | import android.database.Cursor;
29 | import android.graphics.Bitmap;
30 | import android.graphics.BitmapFactory;
31 | import android.net.Uri;
32 | import android.os.Bundle;
33 | import android.provider.MediaStore;
34 | import android.view.LayoutInflater;
35 | import android.view.View;
36 | import android.view.ViewGroup;
37 | import android.widget.Button;
38 | import android.widget.ImageView;
39 |
40 | import com.ultimate.camera.R;
41 | import com.ultimate.camera.activities.MainActivity;
42 |
43 | /**
44 | * Example of loading an image into an image view using the image picker.
45 | *
46 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
47 | */
48 | public class SimpleAndroidImagePickerFragment extends BaseFragment implements Button.OnClickListener {
49 |
50 | // Code for our image picker select action.
51 | private static final int IMAGE_PICKER_SELECT = 999;
52 |
53 | // Reference to our image view we will use
54 | private ImageView mSelectedImage;
55 |
56 | // Reference to picker button.
57 | private Button mPickPhotoButton;
58 |
59 | /**
60 | * Default empty constructor.
61 | */
62 | public SimpleAndroidImagePickerFragment(){
63 | super();
64 | }
65 |
66 | /**
67 | * Static factory method
68 | * @param sectionNumber
69 | * @return
70 | */
71 | public static SimpleAndroidImagePickerFragment newInstance(int sectionNumber) {
72 | SimpleAndroidImagePickerFragment fragment = new SimpleAndroidImagePickerFragment();
73 | Bundle args = new Bundle();
74 | args.putInt(ARG_SECTION_NUMBER, sectionNumber);
75 | fragment.setArguments(args);
76 | return fragment;
77 | }
78 |
79 | /**
80 | * OnCreateView fragment override
81 | * @param inflater
82 | * @param container
83 | * @param savedInstanceState
84 | * @return
85 | */
86 | @Override
87 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
88 | Bundle savedInstanceState) {
89 | View view = null;
90 | view = inflater.inflate(R.layout.fragment_photo_picker, container, false);
91 |
92 | // Set the image view
93 | mSelectedImage = (ImageView)view.findViewById(R.id.imageViewFullSized);
94 | mPickPhotoButton = (Button)view.findViewById(R.id.button);
95 |
96 | // Set OnItemClickListener so we can be notified on button clicks
97 | mPickPhotoButton.setOnClickListener(this);
98 |
99 | return view;
100 | }
101 |
102 | @Override
103 | public void onClick(View view) {
104 | Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
105 | startActivityForResult(i, IMAGE_PICKER_SELECT);
106 | }
107 |
108 | /**
109 | * Photo Selection result
110 | */
111 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
112 | if (requestCode == IMAGE_PICKER_SELECT && resultCode == Activity.RESULT_OK) {
113 | MainActivity activity = (MainActivity)getActivity();
114 | Bitmap bitmap = getBitmapFromCameraData(data, activity);
115 | mSelectedImage.setImageBitmap(bitmap);
116 | }
117 | }
118 |
119 | /**
120 | * Scale the photo down and fit it to our image views.
121 | *
122 | * "Drastically increases performance" to set images using this technique.
123 | * Read more:http://developer.android.com/training/camera/photobasics.html
124 | */
125 | private void setFullImageFromFilePath(String imagePath) {
126 | // Get the dimensions of the View
127 | int targetW = mSelectedImage.getWidth();
128 | int targetH = mSelectedImage.getHeight();
129 |
130 | // Get the dimensions of the bitmap
131 | BitmapFactory.Options bmOptions = new BitmapFactory.Options();
132 | bmOptions.inJustDecodeBounds = true;
133 | BitmapFactory.decodeFile(imagePath, bmOptions);
134 | int photoW = bmOptions.outWidth;
135 | int photoH = bmOptions.outHeight;
136 |
137 | // Determine how much to scale down the image
138 | int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
139 |
140 | // Decode the image file into a Bitmap sized to fill the View
141 | bmOptions.inJustDecodeBounds = false;
142 | bmOptions.inSampleSize = scaleFactor;
143 | bmOptions.inPurgeable = true;
144 |
145 | Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
146 | mSelectedImage.setImageBitmap(bitmap);
147 | }
148 |
149 | /**
150 | * Use for decoding camera response data.
151 | *
152 | * @param data
153 | * @param context
154 | * @return
155 | */
156 | public static Bitmap getBitmapFromCameraData(Intent data, Context context){
157 | Uri selectedImage = data.getData();
158 | String[] filePathColumn = { MediaStore.Images.Media.DATA };
159 | Cursor cursor = context.getContentResolver().query(selectedImage,filePathColumn, null, null, null);
160 | cursor.moveToFirst();
161 | int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
162 | String picturePath = cursor.getString(columnIndex);
163 | cursor.close();
164 | return BitmapFactory.decodeFile(picturePath);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/fragments/SimpleCameraIntentFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.fragments;
24 |
25 | import android.app.Activity;
26 | import android.content.Context;
27 | import android.content.Intent;
28 | import android.content.pm.PackageManager;
29 | import android.graphics.Bitmap;
30 | import android.graphics.BitmapFactory;
31 | import android.net.Uri;
32 | import android.os.Bundle;
33 | import android.os.Environment;
34 | import android.provider.MediaStore;
35 | import android.view.LayoutInflater;
36 | import android.view.View;
37 | import android.view.ViewGroup;
38 | import android.widget.AbsListView;
39 | import android.widget.AdapterView;
40 | import android.widget.Button;
41 | import android.widget.ImageView;
42 | import android.widget.ListAdapter;
43 | import android.widget.RadioGroup;
44 | import android.widget.TextView;
45 | import android.widget.Toast;
46 |
47 | import com.ultimate.camera.R;
48 | import com.ultimate.camera.activities.CameraActivity;
49 | import com.ultimate.camera.utilities.ImageUtil;
50 |
51 | import java.io.File;
52 | import java.io.IOException;
53 | import java.text.SimpleDateFormat;
54 | import java.util.Date;
55 |
56 | /**
57 | * This is an example of a fragment which can use the external Android camera to take
58 | * a picture. It is important to remember to save the file URI where we want to save
59 | * our picture into the bundle because this data will be cleared when the camera is loaded.
60 | * The appropriate place to do this is in the Fragment's parent activity because there isn't a
61 | * good "entry" point when the fragment returns to the foreground to retrieve the bundle info.
62 | *
63 | * Reference: http://developer.android.com/training/camera/photobasics.html
64 | *
65 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
66 | */
67 | public class SimpleCameraIntentFragment extends BaseFragment implements Button.OnClickListener {
68 |
69 | // Activity result key for camera
70 | static final int REQUEST_TAKE_PHOTO = 11111;
71 |
72 | // Image view for showing our image.
73 | private ImageView mImageView;
74 | private ImageView mThumbnailImageView;
75 |
76 | /**
77 | * Default empty constructor.
78 | */
79 | public SimpleCameraIntentFragment(){
80 | super();
81 | }
82 |
83 | /**
84 | * Static factory method
85 | * @param sectionNumber
86 | * @return
87 | */
88 | public static SimpleCameraIntentFragment newInstance(int sectionNumber) {
89 | SimpleCameraIntentFragment fragment = new SimpleCameraIntentFragment();
90 | Bundle args = new Bundle();
91 | args.putInt(ARG_SECTION_NUMBER, sectionNumber);
92 | fragment.setArguments(args);
93 | return fragment;
94 | }
95 |
96 | /**
97 | * OnCreateView fragment override
98 | * @param inflater
99 | * @param container
100 | * @param savedInstanceState
101 | * @return
102 | */
103 | @Override
104 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
105 | Bundle savedInstanceState) {
106 | View view = null;
107 | view = inflater.inflate(R.layout.fragment_simple_camera_intent, container, false);
108 |
109 | // Set the image view
110 | mImageView = (ImageView)view.findViewById(R.id.imageViewFullSized);
111 | mThumbnailImageView = (ImageView)view.findViewById(R.id.imageViewThumbnail);
112 | Button takePictureButton = (Button)view.findViewById(R.id.button);
113 |
114 | // Set OnItemClickListener so we can be notified on button clicks
115 | takePictureButton.setOnClickListener(this);
116 |
117 | return view;
118 | }
119 |
120 | /**
121 | * Start the camera by dispatching a camera intent.
122 | */
123 | protected void dispatchTakePictureIntent() {
124 |
125 | // Check if there is a camera.
126 | Context context = getActivity();
127 | PackageManager packageManager = context.getPackageManager();
128 | if(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA) == false){
129 | Toast.makeText(getActivity(), "This device does not have a camera.", Toast.LENGTH_SHORT)
130 | .show();
131 | return;
132 | }
133 |
134 | // Camera exists? Then proceed...
135 | Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
136 |
137 | // Ensure that there's a camera activity to handle the intent
138 | CameraActivity activity = (CameraActivity)getActivity();
139 | if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {
140 | // Create the File where the photo should go.
141 | // If you don't do this, you may get a crash in some devices.
142 | File photoFile = null;
143 | try {
144 | photoFile = createImageFile();
145 | } catch (IOException ex) {
146 | // Error occurred while creating the File
147 | Toast toast = Toast.makeText(activity, "There was a problem saving the photo...", Toast.LENGTH_SHORT);
148 | toast.show();
149 | }
150 | // Continue only if the File was successfully created
151 | if (photoFile != null) {
152 | Uri fileUri = Uri.fromFile(photoFile);
153 | activity.setCapturedImageURI(fileUri);
154 | activity.setCurrentPhotoPath(fileUri.getPath());
155 | takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
156 | activity.getCapturedImageURI());
157 | startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
158 | }
159 | }
160 | }
161 |
162 | /**
163 | * The activity returns with the photo.
164 | * @param requestCode
165 | * @param resultCode
166 | * @param data
167 | */
168 | @Override
169 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
170 | if (requestCode == REQUEST_TAKE_PHOTO && resultCode == Activity.RESULT_OK) {
171 | addPhotoToGallery();
172 | CameraActivity activity = (CameraActivity)getActivity();
173 |
174 | // Show the full sized image.
175 | setFullImageFromFilePath(activity.getCurrentPhotoPath(), mImageView);
176 | setFullImageFromFilePath(activity.getCurrentPhotoPath(), mThumbnailImageView);
177 | } else {
178 | Toast.makeText(getActivity(), "Image Capture Failed", Toast.LENGTH_SHORT)
179 | .show();
180 | }
181 | }
182 |
183 | /**
184 | * Creates the image file to which the image must be saved.
185 | * @return
186 | * @throws IOException
187 | */
188 | protected File createImageFile() throws IOException {
189 | // Create an image file name
190 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
191 | String imageFileName = "JPEG_" + timeStamp + "_";
192 | File storageDir = Environment.getExternalStoragePublicDirectory(
193 | Environment.DIRECTORY_PICTURES);
194 | File image = File.createTempFile(
195 | imageFileName, /* prefix */
196 | ".jpg", /* suffix */
197 | storageDir /* directory */
198 | );
199 |
200 | // Save a file: path for use with ACTION_VIEW intents
201 | CameraActivity activity = (CameraActivity)getActivity();
202 | activity.setCurrentPhotoPath("file:" + image.getAbsolutePath());
203 | return image;
204 | }
205 |
206 | /**
207 | * Add the picture to the photo gallery.
208 | * Must be called on all camera images or they will
209 | * disappear once taken.
210 | */
211 | protected void addPhotoToGallery() {
212 | Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
213 | CameraActivity activity = (CameraActivity)getActivity();
214 | File f = new File(activity.getCurrentPhotoPath());
215 | Uri contentUri = Uri.fromFile(f);
216 | mediaScanIntent.setData(contentUri);
217 | this.getActivity().sendBroadcast(mediaScanIntent);
218 | }
219 |
220 | /**
221 | * Deal with button clicks.
222 | * @param v
223 | */
224 | @Override
225 | public void onClick(View v) {
226 | dispatchTakePictureIntent();
227 | }
228 |
229 | /**
230 | * Scale the photo down and fit it to our image views.
231 | *
232 | * "Drastically increases performance" to set images using this technique.
233 | * Read more:http://developer.android.com/training/camera/photobasics.html
234 | */
235 | private void setFullImageFromFilePath(String imagePath, ImageView imageView) {
236 | // Get the dimensions of the View
237 | int targetW = imageView.getWidth();
238 | int targetH = imageView.getHeight();
239 |
240 | // Get the dimensions of the bitmap
241 | BitmapFactory.Options bmOptions = new BitmapFactory.Options();
242 | bmOptions.inJustDecodeBounds = true;
243 | BitmapFactory.decodeFile(imagePath, bmOptions);
244 | int photoW = bmOptions.outWidth;
245 | int photoH = bmOptions.outHeight;
246 |
247 | // Determine how much to scale down the image
248 | int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
249 |
250 | // Decode the image file into a Bitmap sized to fill the View
251 | bmOptions.inJustDecodeBounds = false;
252 | bmOptions.inSampleSize = scaleFactor;
253 | bmOptions.inPurgeable = true;
254 |
255 | Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
256 | imageView.setImageBitmap(bitmap);
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/fragments/SimplePhotoGalleryListFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.fragments;
24 |
25 | import android.app.Activity;
26 | import android.app.LoaderManager;
27 | import android.app.ProgressDialog;
28 | import android.content.Context;
29 | import android.content.Loader;
30 | import android.os.Bundle;
31 | import android.view.LayoutInflater;
32 | import android.view.View;
33 | import android.view.ViewGroup;
34 | import android.widget.AbsListView;
35 | import android.widget.AdapterView;
36 | import android.widget.BaseAdapter;
37 | import android.widget.ListAdapter;
38 | import android.widget.TextView;
39 |
40 | import com.ultimate.camera.R;
41 | import com.ultimate.camera.activities.MainActivity;
42 | import com.ultimate.camera.adapters.PhotoAdapter;
43 | import com.ultimate.camera.adapters.items.PhotoItem;
44 | import com.ultimate.camera.utilities.PhotoGalleryAsyncLoader;
45 |
46 | import java.util.ArrayList;
47 | import java.util.Iterator;
48 | import java.util.List;
49 |
50 | /**
51 | * This is an example which will load all the images on your phone into a grid using a background
52 | * image AsyncLoader.
53 | *
54 | * Reference: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
55 | *
56 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
57 | */
58 | public class SimplePhotoGalleryListFragment extends BaseFragment implements AbsListView.OnItemClickListener,
59 | LoaderManager.LoaderCallbacks> {
60 |
61 | // Ivars.
62 | protected OnFragmentInteractionListener mListener;
63 | protected AbsListView mListView;
64 | protected PhotoAdapter mAdapter;
65 | protected ArrayList mPhotoListItem;
66 | protected TextView mEmptyTextView;
67 | protected ProgressDialog mLoadingProgressDialog;
68 |
69 | /**
70 | * Required empty constructor
71 | */
72 | public SimplePhotoGalleryListFragment() {
73 | super();
74 | }
75 |
76 | /**
77 | * Static factory method
78 | * @param sectionNumber
79 | * @return
80 | */
81 | public static SimplePhotoGalleryListFragment newInstance(int sectionNumber) {
82 | SimplePhotoGalleryListFragment fragment = new SimplePhotoGalleryListFragment();
83 | Bundle args = new Bundle();
84 | args.putInt(ARG_SECTION_NUMBER, sectionNumber);
85 | fragment.setArguments(args);
86 | return fragment;
87 | }
88 |
89 | @Override
90 | public void onCreate(Bundle savedInstanceState) {
91 | super.onCreate(savedInstanceState);
92 |
93 | // Create an empty loader and pre-initialize the photo list items as an empty list.
94 | Context context = getActivity().getBaseContext();
95 |
96 | // Set up empty mAdapter
97 | mPhotoListItem = new ArrayList() ;
98 | mAdapter = new PhotoAdapter(context,
99 | R.layout.photo_item,
100 | mPhotoListItem, false);
101 |
102 | // Prepare the loader. Either re-connect with an existing one,
103 | // or start a new one.
104 | getLoaderManager().initLoader(0, null, this);
105 | }
106 |
107 | @Override
108 | public View onCreateView(LayoutInflater inflater,
109 | ViewGroup container,
110 | Bundle savedInstanceState) {
111 | View view = null;
112 | view = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
113 |
114 | // Set the mAdapter
115 | mListView = (AbsListView) view.findViewById(android.R.id.list);
116 | ((AdapterView) mListView).setAdapter(mAdapter);
117 | mEmptyTextView = (TextView)view.findViewById(R.id.empty);
118 |
119 | // Show the empty text / message.
120 | resolveEmptyText();
121 |
122 | // Set OnItemClickListener so we can be notified on item clicks
123 | mListView.setOnItemClickListener(this);
124 |
125 | return view;
126 | }
127 |
128 | /**
129 | * Used to show a generic empty text warning. Override in inheriting classes.
130 | */
131 | protected void resolveEmptyText(){
132 | if(mAdapter.isEmpty()){
133 | mEmptyTextView.setVisibility(View.VISIBLE);
134 | setEmptyText();
135 | } else {
136 | mEmptyTextView.setVisibility(View.INVISIBLE);
137 | }
138 | }
139 |
140 | @Override
141 | public void onAttach(Activity activity) {
142 | super.onAttach(activity);
143 | try {
144 | mListener = (OnFragmentInteractionListener) activity;
145 | // Show a progress dialog.
146 | mLoadingProgressDialog = new ProgressDialog(getActivity());
147 | mLoadingProgressDialog.setMessage("Loading Photos...");
148 | mLoadingProgressDialog.setCancelable(true);
149 | mLoadingProgressDialog.show();
150 | } catch (ClassCastException e) {
151 | throw new ClassCastException(activity.toString()
152 | + " must implement OnFragmentInteractionListener");
153 | }
154 | }
155 |
156 | @Override
157 | public void onDetach() {
158 | super.onDetach();
159 | mListener = null;
160 | cancelProgressDialog();
161 | }
162 |
163 | @Override
164 | public void onPause(){
165 | super.onPause();
166 | cancelProgressDialog();
167 | }
168 |
169 | @Override
170 | public void onStop(){
171 | super.onStop();
172 | cancelProgressDialog();
173 | }
174 |
175 | /**
176 | * This is only triggered when the user selects a single photo.
177 | * @param parent
178 | * @param view
179 | * @param position
180 | * @param id
181 | */
182 |
183 | @Override
184 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
185 | if (null != mListener) {
186 | // Tell the share builder to add the photo to the share operation.
187 | PhotoItem photoListItem = (PhotoItem)this.mAdapter.getItem(position);
188 | String imagePath = photoListItem.getThumbnailUri().getPath();
189 | mListener.onFragmentInteraction(MainActivity.SELECT_PHOTO_ACTION);
190 | resetFragmentState();
191 | }
192 | }
193 |
194 | /**
195 | * Used when hitting the back button to reset the mFragment UI state
196 | */
197 | protected void resetFragmentState(){
198 | // Clear view state
199 | getActivity().invalidateOptionsMenu();
200 | ((BaseAdapter) mListView.getAdapter()).notifyDataSetChanged();
201 | }
202 |
203 | /**
204 | * The default content for this Fragment has a TextView that is shown when
205 | * the list is empty. If you would like to change the text, call this method
206 | * to supply the text it should use.
207 | */
208 | public void setEmptyText() {
209 | mEmptyTextView.setText("No Photos!");
210 | }
211 |
212 | /**
213 | * Loader Handlers for loading the photos in the background.
214 | */
215 | @Override
216 | public Loader> onCreateLoader(int id, Bundle args) {
217 | // This is called when a new Loader needs to be created. This
218 | // sample only has one Loader with no arguments, so it is simple.
219 | return new PhotoGalleryAsyncLoader(getActivity());
220 | }
221 |
222 | @Override
223 | public void onLoadFinished(Loader> loader, List data) {
224 | // Set the new data in the mAdapter.
225 | mPhotoListItem.clear();
226 |
227 | for(int i = 0; i < data.size();i++){
228 | PhotoItem item = data.get(i);
229 | mPhotoListItem.add(item);
230 | }
231 |
232 | mAdapter.notifyDataSetChanged();
233 | resolveEmptyText();
234 | cancelProgressDialog();
235 | }
236 |
237 | @Override
238 | public void onLoaderReset(Loader> loader) {
239 | // Clear the data in the mAdapter.
240 | mPhotoListItem.clear();
241 | mAdapter.notifyDataSetChanged();
242 | resolveEmptyText();
243 | cancelProgressDialog();
244 | }
245 |
246 | /**
247 | * Save cancel for the progress loader
248 | */
249 | private void cancelProgressDialog(){
250 | if(mLoadingProgressDialog != null){
251 | if(mLoadingProgressDialog.isShowing()){
252 | mLoadingProgressDialog.cancel();
253 | }
254 | }
255 | }
256 | }
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/utilities/DeviceInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.utilities;
24 |
25 | import android.bluetooth.BluetoothAdapter;
26 | import android.os.Build;
27 |
28 | /**
29 | * Utility for fetching details about the device.
30 | *
31 | * Created by Rex St. John (on behalf of AirPair.com) on 3/6/14.
32 | */
33 | public class DeviceInfo {
34 |
35 | /**
36 | * Get the device's manufacturer name string.
37 | * @return
38 | */
39 | public static String getDeviceName() {
40 | String manufacturer = Build.MANUFACTURER;
41 | String model = Build.MODEL;
42 | if (model.startsWith(manufacturer)) {
43 | return capitalize(model);
44 | } else {
45 | return capitalize(manufacturer) + " " + model;
46 | }
47 | }
48 |
49 | /**
50 | * Get the device's UUID
51 | * @return
52 | */
53 | public static String getDeviceUUID(){
54 | BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
55 | String uuid = adapter.getAddress();
56 | return uuid;
57 | }
58 |
59 | /**
60 | * Internal helper to capitalize the string properly.
61 | * @param s
62 | * @return
63 | */
64 | private static String capitalize(String s) {
65 | if (s == null || s.length() == 0) {
66 | return "";
67 | }
68 | char first = s.charAt(0);
69 | if (Character.isUpperCase(first)) {
70 | return s;
71 | } else {
72 | return Character.toUpperCase(first) + s.substring(1);
73 | }
74 | }
75 |
76 | /**
77 | * Is this application an emulator?
78 | * @return
79 | */
80 | public static boolean isEmulator(){
81 | String brand = Build.BRAND;
82 | if (brand.equalsIgnoreCase("generic")) {
83 | return true;
84 | } else {
85 | return false;
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/utilities/DialogHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.utilities;
24 |
25 | import android.app.AlertDialog;
26 | import android.content.Context;
27 | import android.content.DialogInterface;
28 |
29 | /**
30 | * Created by Rex St. John (on behalf of AirPair.com) on 3/6/14.
31 | */
32 | public class DialogHelper {
33 |
34 | /**
35 | * Generic error dialog with a close button.
36 | * @param title
37 | * @param message
38 | * @param context
39 | */
40 | public static void showDialog(String title, String message, Context context){
41 | AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
42 | context);
43 | alertDialogBuilder.setTitle(title);
44 | alertDialogBuilder
45 | .setMessage(message)
46 | .setCancelable(false)
47 | .setPositiveButton("Close",new DialogInterface.OnClickListener() {
48 | public void onClick(DialogInterface dialog,int id) {
49 | dialog.cancel();
50 | }
51 | });
52 | AlertDialog alertDialog = alertDialogBuilder.create();
53 | alertDialog.show();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/utilities/ImageUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.utilities;
24 |
25 | import android.content.Context;
26 | import android.content.Intent;
27 | import android.database.Cursor;
28 | import android.graphics.Bitmap;
29 | import android.graphics.BitmapFactory;
30 | import android.net.Uri;
31 | import android.provider.MediaStore;
32 |
33 | /**
34 | * Created by Rex St. John (on behalf of AirPair.com) on 3/6/14.
35 | */
36 | public class ImageUtil {
37 |
38 | /**
39 | * Get thumbnail as a bitmap from a path given a resolution
40 | * @param path
41 | * @param thumbnailSize
42 | * @return
43 | */
44 | public static Bitmap getThumbnailBitmap(String path, int thumbnailSize) {
45 | BitmapFactory.Options bounds = new BitmapFactory.Options();
46 | bounds.inJustDecodeBounds = true;
47 | BitmapFactory.decodeFile(path, bounds);
48 | if ((bounds.outWidth == -1) || (bounds.outHeight == -1)) {
49 | return null;
50 | }
51 | int originalSize = (bounds.outHeight > bounds.outWidth) ? bounds.outHeight
52 | : bounds.outWidth;
53 | BitmapFactory.Options opts = new BitmapFactory.Options();
54 | opts.inSampleSize = originalSize / thumbnailSize;
55 | return BitmapFactory.decodeFile(path, opts);
56 | }
57 |
58 | /**
59 | * Use for decoding camera response data.
60 | *
61 | * Example call:
62 | * Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
63 | startActivityForResult(i, R.integer.PHOTO_SELECT_ACTION);
64 | *
65 | * @param data
66 | * @param context
67 | * @return
68 | */
69 | public static Bitmap getBitmapFromCameraData(Intent data, Context context){
70 | Uri selectedImage = data.getData();
71 | String[] filePathColumn = { MediaStore.Images.Media.DATA };
72 | Cursor cursor = context.getContentResolver().query(selectedImage,filePathColumn, null, null, null);
73 | cursor.moveToFirst();
74 | int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
75 | String picturePath = cursor.getString(columnIndex);
76 | cursor.close();
77 | return BitmapFactory.decodeFile(picturePath);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/utilities/PhotoGalleryAsyncLoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.utilities;
24 |
25 | import android.content.AsyncTaskLoader;
26 | import android.content.Context;
27 | import android.os.Environment;
28 |
29 | import java.util.List;
30 |
31 | import android.content.AsyncTaskLoader;
32 | import android.content.Context;
33 |
34 | import com.ultimate.camera.adapters.items.PhotoItem;
35 |
36 | import java.util.List;
37 |
38 | /**
39 | * AsyncTask loader used to load image resources in the background of a fragment.
40 | * Reference: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
41 | *
42 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
43 | */
44 | public class PhotoGalleryAsyncLoader extends AsyncTaskLoader> {
45 |
46 | // Persistent list of photo list item
47 | private List mPhotoListItems;
48 |
49 | /**
50 | * Constructor
51 | * @param context
52 | */
53 | public PhotoGalleryAsyncLoader(Context context) {
54 | super(context);
55 | }
56 |
57 | /**
58 | * Matches code in MediaProvider.computeBucketValues.
59 | */
60 | public static String getBucketId(String path) {
61 | return String.valueOf(path.toLowerCase().hashCode());
62 | }
63 |
64 | /**
65 | * Load photo album image items in the background
66 | *
67 | * This is where the bulk of our work is done. This function is
68 | * called in a background thread and should generate a new set of
69 | * data to be published by the loader.
70 | */
71 | @Override
72 | public List loadInBackground() {
73 | final Context context = getContext();
74 | List photos = PhotoGalleryImageProvider.getAlbumThumbnails(context);
75 | return photos;
76 | }
77 |
78 | /**
79 | * Called when there is new data to deliver to the client. The
80 | * super class will take care of delivering it; the implementation
81 | * here just adds a little more logic.
82 | */
83 | @Override public void deliverResult(List newPhotoListItems) {
84 | if (isReset()) {
85 | // An async query came in while the loader is stopped. We
86 | // don't need the result.
87 | if (newPhotoListItems != null) {
88 | onReleaseResources(newPhotoListItems);
89 | }
90 | }
91 | List oldPhotos = mPhotoListItems;
92 | mPhotoListItems = newPhotoListItems;
93 |
94 | if (isStarted()) {
95 | // If the Loader is currently started, we can immediately
96 | // deliver its results.
97 | super.deliverResult(newPhotoListItems);
98 | }
99 |
100 | // At this point we can release the resources associated with
101 | // 'oldApps' if needed; now that the new result is delivered we
102 | // know that it is no longer in use.
103 | if (oldPhotos != null) {
104 | onReleaseResources(oldPhotos);
105 | }
106 | }
107 |
108 | /**
109 | * Handles a request to start the Loader.
110 | */
111 | @Override protected void onStartLoading() {
112 |
113 | if (mPhotoListItems != null) {
114 | // If we currently have a result available, deliver it
115 | // immediately.
116 | deliverResult(mPhotoListItems);
117 | } else {
118 | // If the data has changed since the last time it was loaded
119 | // or is not currently available, start a load.
120 | forceLoad();
121 | }
122 | }
123 |
124 | /**
125 | * Handles a request to stop the Loader.
126 | */
127 | @Override protected void onStopLoading() {
128 | // Attempt to cancel the current load task if possible.
129 | cancelLoad();
130 | }
131 |
132 | /**
133 | * Handles a request to cancel a load.
134 | */
135 | @Override public void onCanceled(List photoListItems) {
136 | super.onCanceled(photoListItems);
137 |
138 | // At this point we can release the resources associated with 'apps'
139 | // if needed.
140 | onReleaseResources(photoListItems);
141 | }
142 |
143 | /**
144 | * Handles a request to completely reset the Loader.
145 | */
146 | @Override protected void onReset() {
147 | super.onReset();
148 |
149 | // Ensure the loader is stopped
150 | onStopLoading();
151 |
152 | // At this point we can release the resources associated with 'apps'
153 | // if needed.
154 | if (mPhotoListItems != null) {
155 | onReleaseResources(mPhotoListItems);
156 | mPhotoListItems = null;
157 | }
158 | }
159 |
160 | /**
161 | * Helper function to take care of releasing resources associated
162 | * with an actively loaded data set.
163 | */
164 | protected void onReleaseResources(List photoListItems) {
165 | // For a simple List<> there is nothing to do. For something
166 | // like a Cursor, we would close it here.
167 | }
168 | }
--------------------------------------------------------------------------------
/camera/src/main/java/com/ultimate/camera/utilities/PhotoGalleryImageProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ultimate.camera.utilities;
24 |
25 | import android.content.Context;
26 | import android.content.CursorLoader;
27 | import android.database.Cursor;
28 | import android.graphics.Bitmap;
29 | import android.graphics.BitmapFactory;
30 | import android.net.Uri;
31 | import android.os.Environment;
32 | import android.provider.MediaStore;
33 |
34 | import com.ultimate.camera.adapters.items.PhotoItem;
35 |
36 | import java.io.File;
37 | import java.util.ArrayList;
38 | import java.util.List;
39 |
40 | /**
41 | * This is a helper utility which automatically fetches paths to full size and thumbnail sized gallery images.
42 | *
43 | * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
44 | */
45 | public class PhotoGalleryImageProvider {
46 |
47 | // Consts
48 | public static final int IMAGE_RESOLUTION = 15;
49 |
50 | // Buckets where we are fetching images from.
51 | public static final String CAMERA_IMAGE_BUCKET_NAME =
52 | Environment.getExternalStorageDirectory().toString()
53 | + "/DCIM/Camera";
54 | public static final String CAMERA_IMAGE_BUCKET_ID =
55 | getBucketId(CAMERA_IMAGE_BUCKET_NAME);
56 |
57 | /**
58 | * Fetch both full sized images and thumbnails via a single query.
59 | * Returns all images not in the Camera Roll.
60 | * @param context
61 | * @return
62 | */
63 | public static List getAlbumThumbnails(Context context){
64 |
65 | final String[] projection = {MediaStore.Images.Thumbnails.DATA,MediaStore.Images.Thumbnails.IMAGE_ID};
66 |
67 | Cursor thumbnailsCursor = context.getContentResolver().query( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
68 | projection, // Which columns to return
69 | null, // Return all rows
70 | null,
71 | null);
72 |
73 | // Extract the proper column thumbnails
74 | int thumbnailColumnIndex = thumbnailsCursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA);
75 | ArrayList result = new ArrayList(thumbnailsCursor.getCount());
76 |
77 | if (thumbnailsCursor.moveToFirst()) {
78 | do {
79 | // Generate a tiny thumbnail version.
80 | int thumbnailImageID = thumbnailsCursor.getInt(thumbnailColumnIndex);
81 | String thumbnailPath = thumbnailsCursor.getString(thumbnailImageID);
82 | Uri thumbnailUri = Uri.parse(thumbnailPath);
83 | Uri fullImageUri = uriToFullImage(thumbnailsCursor,context);
84 |
85 | // Create the list item.
86 | PhotoItem newItem = new PhotoItem(thumbnailUri,fullImageUri);
87 | result.add(newItem);
88 | } while (thumbnailsCursor.moveToNext());
89 | }
90 | thumbnailsCursor.close();
91 | return result;
92 | }
93 |
94 | /**
95 | * Get the path to the full image for a given thumbnail.
96 | */
97 | private static Uri uriToFullImage(Cursor thumbnailsCursor, Context context){
98 | String imageId = thumbnailsCursor.getString(thumbnailsCursor.getColumnIndex(MediaStore.Images.Thumbnails.IMAGE_ID));
99 |
100 | // Request image related to this thumbnail
101 | String[] filePathColumn = { MediaStore.Images.Media.DATA };
102 | Cursor imagesCursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, filePathColumn, MediaStore.Images.Media._ID + "=?", new String[]{imageId}, null);
103 |
104 | if (imagesCursor != null && imagesCursor.moveToFirst()) {
105 | int columnIndex = imagesCursor.getColumnIndex(filePathColumn[0]);
106 | String filePath = imagesCursor.getString(columnIndex);
107 | imagesCursor.close();
108 | return Uri.parse(filePath);
109 | } else {
110 | imagesCursor.close();
111 | return Uri.parse("");
112 | }
113 | }
114 |
115 | /**
116 | * Render a thumbnail photo and scale it down to a smaller size.
117 | * @param path
118 | * @return
119 | */
120 | private static Bitmap bitmapFromPath(String path){
121 | File imgFile = new File(path);
122 | Bitmap imageBitmap = null;
123 |
124 | if(imgFile.exists()){
125 | BitmapFactory.Options options = new BitmapFactory.Options();
126 | options.inSampleSize = IMAGE_RESOLUTION;
127 | imageBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), options);
128 | }
129 | return imageBitmap;
130 | }
131 |
132 | /**
133 | * Matches code in MediaProvider.computeBucketValues. Should be a common
134 | * function.
135 | */
136 | public static String getBucketId(String path) {
137 | return String.valueOf(path.toLowerCase().hashCode());
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-hdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-hdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-hdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-hdpi/ic_drawer.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-mdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-mdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-mdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-mdpi/ic_drawer.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-xhdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-xhdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-xhdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-xhdpi/ic_drawer.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-xxhdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-xxhdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-xxhdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-xxhdpi/ic_drawer.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/camera/src/main/res/drawable/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/camera/src/main/res/drawable/placeholder.png
--------------------------------------------------------------------------------
/camera/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
31 |
32 |
34 |
38 |
39 |
44 |
46 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_horizontal_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
28 |
29 |
39 |
45 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
22 |
23 |
32 |
33 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_native_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
30 |
36 |
37 |
38 |
43 |
51 |
52 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_photo_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
29 |
32 |
36 |
42 |
43 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_photo_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
28 |
29 |
35 |
36 |
44 |
45 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/fragment_simple_camera_intent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
28 |
29 |
35 |
36 |
43 |
44 |
52 |
53 |
--------------------------------------------------------------------------------
/camera/src/main/res/layout/photo_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
28 |
31 |
38 |
39 |
--------------------------------------------------------------------------------
/camera/src/main/res/menu/global.xml:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/camera/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
22 |
23 |
29 |
--------------------------------------------------------------------------------
/camera/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/camera/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/camera/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 | 16dp
26 | 16dp
27 |
28 |
30 | 240dp
31 |
32 |
33 | 120dp
34 | 120dp
35 |
36 |
--------------------------------------------------------------------------------
/camera/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 |
26 | Ultimate Android Camera Guide
27 | Open navigation drawer
28 | Close navigation drawer
29 | Example action
30 | Settings
31 |
32 |
33 | Simple Camera Intent
34 | Photo Gallery Using Loaders
35 | Image Picker
36 | Native Camera
37 | Horizontal Gallery
38 |
39 |
40 |
--------------------------------------------------------------------------------
/camera/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
43 |
44 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rexstjohn/UltimateAndroidCameraGuide/f0e00202c1c9f299e958a8ea295ebd21f5d10574/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Mar 23 09:05:41 PDT 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':camera'
2 |
--------------------------------------------------------------------------------
/ultimate.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------