• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.camera.settings;
18 
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
25 import android.os.Bundle;
26 import android.preference.ListPreference;
27 import android.preference.Preference;
28 import android.preference.Preference.OnPreferenceClickListener;
29 import android.preference.PreferenceFragment;
30 import android.preference.PreferenceGroup;
31 import android.preference.PreferenceScreen;
32 import android.support.v4.app.FragmentActivity;
33 import android.view.MenuItem;
34 
35 import com.android.camera.debug.Log;
36 import com.android.camera.settings.SettingsUtil.SelectedPictureSizes;
37 import com.android.camera.settings.SettingsUtil.SelectedVideoQualities;
38 import com.android.camera.util.CameraSettingsActivityHelper;
39 import com.android.camera.util.GoogleHelpHelper;
40 import com.android.camera2.R;
41 import com.android.ex.camera2.portability.CameraAgentFactory;
42 import com.android.ex.camera2.portability.CameraDeviceInfo;
43 import com.android.ex.camera2.portability.Size;
44 
45 import java.text.DecimalFormat;
46 import java.util.ArrayList;
47 import java.util.List;
48 
49 /**
50  * Provides the settings UI for the Camera app.
51  */
52 public class CameraSettingsActivity extends FragmentActivity {
53     /**
54      * Used to denote a subsection of the preference tree to display in the
55      * Fragment. For instance, if 'Advanced' key is provided, the advanced
56      * preference section will be treated as the root for display. This is used
57      * to enable activity transitions between preference sections, and allows
58      * back/up stack to operate correctly.
59      */
60     public static final String PREF_SCREEN_EXTRA = "pref_screen_extra";
61 
62     @Override
onCreate(Bundle savedInstanceState)63     public void onCreate(Bundle savedInstanceState) {
64         super.onCreate(savedInstanceState);
65 
66         ActionBar actionBar = getActionBar();
67         actionBar.setDisplayHomeAsUpEnabled(true);
68         actionBar.setTitle(R.string.mode_settings);
69 
70         String prefKey = getIntent().getStringExtra(PREF_SCREEN_EXTRA);
71         CameraSettingsFragment dialog = new CameraSettingsFragment();
72         Bundle bundle = new Bundle(1);
73         bundle.putString(PREF_SCREEN_EXTRA, prefKey);
74         dialog.setArguments(bundle);
75         getFragmentManager().beginTransaction().replace(android.R.id.content, dialog).commit();
76     }
77 
78     @Override
onMenuItemSelected(int featureId, MenuItem item)79     public boolean onMenuItemSelected(int featureId, MenuItem item) {
80         int itemId = item.getItemId();
81         if (itemId == android.R.id.home) {
82             finish();
83             return true;
84         }
85         return true;
86     }
87 
88     public static class CameraSettingsFragment extends PreferenceFragment implements
89             OnSharedPreferenceChangeListener {
90 
91         public static final String PREF_CATEGORY_RESOLUTION = "pref_category_resolution";
92         public static final String PREF_CATEGORY_ADVANCED = "pref_category_advanced";
93         public static final String PREF_LAUNCH_HELP = "pref_launch_help";
94         private static final Log.Tag TAG = new Log.Tag("SettingsFragment");
95         private static DecimalFormat sMegaPixelFormat = new DecimalFormat("##0.0");
96         private String[] mCamcorderProfileNames;
97         private CameraDeviceInfo mInfos;
98         private String mPrefKey;
99         private boolean mGetSubPrefAsRoot = true;
100 
101         // Selected resolutions for the different cameras and sizes.
102         private SelectedPictureSizes mOldPictureSizesBack;
103         private SelectedPictureSizes mOldPictureSizesFront;
104         private List<Size> mPictureSizesBack;
105         private List<Size> mPictureSizesFront;
106         private SelectedVideoQualities mVideoQualitiesBack;
107         private SelectedVideoQualities mVideoQualitiesFront;
108 
109         @Override
onCreate(Bundle savedInstanceState)110         public void onCreate(Bundle savedInstanceState) {
111             super.onCreate(savedInstanceState);
112             Bundle arguments = getArguments();
113             if (arguments != null) {
114                 mPrefKey = arguments.getString(PREF_SCREEN_EXTRA);
115             }
116             Context context = this.getActivity().getApplicationContext();
117             addPreferencesFromResource(R.xml.camera_preferences);
118 
119             // Allow the Helper to edit the full preference hierarchy, not the sub
120             // tree we may show as root. See {@link #getPreferenceScreen()}.
121             mGetSubPrefAsRoot = false;
122             CameraSettingsActivityHelper.addAdditionalPreferences(this, context);
123             mGetSubPrefAsRoot = true;
124 
125             mCamcorderProfileNames = getResources().getStringArray(R.array.camcorder_profile_names);
126             mInfos = CameraAgentFactory
127                     .getAndroidCameraAgent(context, CameraAgentFactory.CameraApi.API_1)
128                     .getCameraDeviceInfo();
129         }
130 
131         @Override
onResume()132         public void onResume() {
133             super.onResume();
134             final Activity activity = this.getActivity();
135 
136             // Load the camera sizes.
137             loadSizes();
138 
139             // Make sure to hide settings for cameras that don't exist on this
140             // device.
141             setVisibilities();
142 
143             // Put in the summaries for the currently set values.
144             final PreferenceScreen resolutionScreen =
145                     (PreferenceScreen) findPreference(PREF_CATEGORY_RESOLUTION);
146             fillEntriesAndSummaries(resolutionScreen);
147             setPreferenceScreenIntent(resolutionScreen);
148 
149             final PreferenceScreen advancedScreen =
150                 (PreferenceScreen) findPreference(PREF_CATEGORY_ADVANCED);
151             setPreferenceScreenIntent(advancedScreen);
152 
153             Preference helpPref = findPreference(PREF_LAUNCH_HELP);
154             helpPref.setOnPreferenceClickListener(
155                 new OnPreferenceClickListener() {
156                     @Override
157                     public boolean onPreferenceClick(Preference preference) {
158                         GoogleHelpHelper.launchGoogleHelp(activity);
159                         return true;
160                     }
161                 });
162             getPreferenceScreen().getSharedPreferences()
163                     .registerOnSharedPreferenceChangeListener(this);
164         }
165 
166         /**
167          * Configure home-as-up for sub-screens.
168          */
setPreferenceScreenIntent(final PreferenceScreen preferenceScreen)169         private void setPreferenceScreenIntent(final PreferenceScreen preferenceScreen) {
170             Intent intent = new Intent(getActivity(), CameraSettingsActivity.class);
171             intent.putExtra(PREF_SCREEN_EXTRA, preferenceScreen.getKey());
172             preferenceScreen.setIntent(intent);
173         }
174 
175         /**
176          * This override allows the CameraSettingsFragment to be reused for
177          * different nested PreferenceScreens within the single camera
178          * preferences XML resource. If the fragment is constructed with a
179          * desired preference key (delivered via an extra in the creation
180          * intent), it is used to look up the nested PreferenceScreen and
181          * returned here.
182          */
183         @Override
getPreferenceScreen()184         public PreferenceScreen getPreferenceScreen() {
185             PreferenceScreen root = super.getPreferenceScreen();
186             if (!mGetSubPrefAsRoot || mPrefKey == null || root == null) {
187                 return root;
188             } else {
189                 PreferenceScreen match = findByKey(root, mPrefKey);
190                 if (match != null) {
191                     return match;
192                 } else {
193                     throw new RuntimeException("key " + mPrefKey + " not found");
194                 }
195             }
196         }
197 
findByKey(PreferenceScreen parent, String key)198         private PreferenceScreen findByKey(PreferenceScreen parent, String key) {
199             if (key.equals(parent.getKey())) {
200                 return parent;
201             } else {
202                 for (int i = 0; i < parent.getPreferenceCount(); i++) {
203                     Preference child = parent.getPreference(i);
204                     if (child instanceof PreferenceScreen) {
205                         PreferenceScreen match = findByKey((PreferenceScreen) child, key);
206                         if (match != null) {
207                             return match;
208                         }
209                     }
210                 }
211                 return null;
212             }
213         }
214 
215         /**
216          * Depending on camera availability on the device, this removes settings
217          * for cameras the device doesn't have.
218          */
setVisibilities()219         private void setVisibilities() {
220             PreferenceGroup resolutions =
221                     (PreferenceGroup) findPreference(PREF_CATEGORY_RESOLUTION);
222             if (mPictureSizesBack == null) {
223                 recursiveDelete(resolutions,
224                         findPreference(Keys.KEY_PICTURE_SIZE_BACK));
225                 recursiveDelete(resolutions,
226                         findPreference(Keys.KEY_VIDEO_QUALITY_BACK));
227             }
228             if (mPictureSizesFront == null) {
229                 recursiveDelete(resolutions,
230                         findPreference(Keys.KEY_PICTURE_SIZE_FRONT));
231                 recursiveDelete(resolutions,
232                         findPreference(Keys.KEY_VIDEO_QUALITY_FRONT));
233             }
234         }
235 
236         /**
237          * Recursively go through settings and fill entries and summaries of our
238          * preferences.
239          */
fillEntriesAndSummaries(PreferenceGroup group)240         private void fillEntriesAndSummaries(PreferenceGroup group) {
241             for (int i = 0; i < group.getPreferenceCount(); ++i) {
242                 Preference pref = group.getPreference(i);
243                 if (pref instanceof PreferenceGroup) {
244                     fillEntriesAndSummaries((PreferenceGroup) pref);
245                 }
246                 setSummary(pref);
247                 setEntries(pref);
248             }
249         }
250 
251         /**
252          * Recursively traverses the tree from the given group as the route and
253          * tries to delete the preference. Traversal stops once the preference
254          * was found and removed.
255          */
recursiveDelete(PreferenceGroup group, Preference preference)256         private boolean recursiveDelete(PreferenceGroup group, Preference preference) {
257             if (group == null) {
258                 Log.d(TAG, "attempting to delete from null preference group");
259                 return false;
260             }
261             if (preference == null) {
262                 Log.d(TAG, "attempting to delete null preference");
263                 return false;
264             }
265             if (group.removePreference(preference)) {
266                 // Removal was successful.
267                 return true;
268             }
269 
270             for (int i = 0; i < group.getPreferenceCount(); ++i) {
271                 Preference pref = group.getPreference(i);
272                 if (pref instanceof PreferenceGroup) {
273                     if (recursiveDelete((PreferenceGroup) pref, preference)) {
274                         return true;
275                     }
276                 }
277             }
278             return false;
279         }
280 
281         @Override
onPause()282         public void onPause() {
283             super.onPause();
284             getPreferenceScreen().getSharedPreferences()
285                     .unregisterOnSharedPreferenceChangeListener(this);
286         }
287 
288         @Override
onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)289         public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
290             setSummary(findPreference(key));
291         }
292 
293         /**
294          * Set the entries for the given preference. The given preference needs
295          * to be a {@link ListPreference}
296          */
setEntries(Preference preference)297         private void setEntries(Preference preference) {
298             if (!(preference instanceof ListPreference)) {
299                 return;
300             }
301 
302             ListPreference listPreference = (ListPreference) preference;
303             if (listPreference.getKey().equals(Keys.KEY_PICTURE_SIZE_BACK)) {
304                 setEntriesForSelection(mPictureSizesBack, listPreference);
305             } else if (listPreference.getKey().equals(Keys.KEY_PICTURE_SIZE_FRONT)) {
306                 setEntriesForSelection(mPictureSizesFront, listPreference);
307             } else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_BACK)) {
308                 setEntriesForSelection(mVideoQualitiesBack, listPreference);
309             } else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_FRONT)) {
310                 setEntriesForSelection(mVideoQualitiesFront, listPreference);
311             }
312         }
313 
314         /**
315          * Set the summary for the given preference. The given preference needs
316          * to be a {@link ListPreference}.
317          */
setSummary(Preference preference)318         private void setSummary(Preference preference) {
319             if (!(preference instanceof ListPreference)) {
320                 return;
321             }
322 
323             ListPreference listPreference = (ListPreference) preference;
324             if (listPreference.getKey().equals(Keys.KEY_PICTURE_SIZE_BACK)) {
325                 setSummaryForSelection(mOldPictureSizesBack, mPictureSizesBack, listPreference);
326             } else if (listPreference.getKey().equals(Keys.KEY_PICTURE_SIZE_FRONT)) {
327                 setSummaryForSelection(mOldPictureSizesFront, mPictureSizesFront, listPreference);
328             } else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_BACK)) {
329                 setSummaryForSelection(mVideoQualitiesBack, listPreference);
330             } else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_FRONT)) {
331                 setSummaryForSelection(mVideoQualitiesFront, listPreference);
332             } else {
333                 listPreference.setSummary(listPreference.getEntry());
334             }
335         }
336 
337         /**
338          * Sets the entries for the given list preference.
339          *
340          * @param selectedSizes The possible S,M,L entries the user can
341          *            choose from.
342          * @param preference The preference to set the entries for.
343          */
setEntriesForSelection(List<Size> selectedSizes, ListPreference preference)344         private void setEntriesForSelection(List<Size> selectedSizes,
345                 ListPreference preference) {
346             if (selectedSizes == null) {
347                 return;
348             }
349 
350             String[] entries = new String[selectedSizes.size()];
351             String[] entryValues = new String[selectedSizes.size()];
352             for (int i = 0; i < selectedSizes.size(); i++) {
353                 Size size = selectedSizes.get(i);
354                 entries[i] = getSizeSummaryString(size);
355                 entryValues[i] = SettingsUtil.sizeToSetting(size);
356             }
357             preference.setEntries(entries);
358             preference.setEntryValues(entryValues);
359         }
360 
361         /**
362          * Sets the entries for the given list preference.
363          *
364          * @param selectedQualities The possible S,M,L entries the user can
365          *            choose from.
366          * @param preference The preference to set the entries for.
367          */
setEntriesForSelection(SelectedVideoQualities selectedQualities, ListPreference preference)368         private void setEntriesForSelection(SelectedVideoQualities selectedQualities,
369                 ListPreference preference) {
370             if (selectedQualities == null) {
371                 return;
372             }
373 
374             // Avoid adding double entries at the bottom of the list which
375             // indicates that not at least 3 qualities are supported.
376             ArrayList<String> entries = new ArrayList<String>();
377             entries.add(mCamcorderProfileNames[selectedQualities.large]);
378             if (selectedQualities.medium != selectedQualities.large) {
379                 entries.add(mCamcorderProfileNames[selectedQualities.medium]);
380             }
381             if (selectedQualities.small != selectedQualities.medium) {
382                 entries.add(mCamcorderProfileNames[selectedQualities.small]);
383             }
384             preference.setEntries(entries.toArray(new String[0]));
385         }
386 
387         /**
388          * Sets the summary for the given list preference.
389          *
390          * @param oldPictureSizes The old selected picture sizes for small medium and large
391          * @param displayableSizes The human readable preferred sizes
392          * @param preference The preference for which to set the summary.
393          */
setSummaryForSelection(SelectedPictureSizes oldPictureSizes, List<Size> displayableSizes, ListPreference preference)394         private void setSummaryForSelection(SelectedPictureSizes oldPictureSizes,
395                 List<Size> displayableSizes, ListPreference preference) {
396             if (oldPictureSizes == null) {
397                 return;
398             }
399 
400             String setting = preference.getValue();
401             Size selectedSize = oldPictureSizes.getFromSetting(setting, displayableSizes);
402 
403             preference.setSummary(getSizeSummaryString(selectedSize));
404         }
405 
406         /**
407          * Sets the summary for the given list preference.
408          *
409          * @param selectedQualities The selected video qualities.
410          * @param preference The preference for which to set the summary.
411          */
setSummaryForSelection(SelectedVideoQualities selectedQualities, ListPreference preference)412         private void setSummaryForSelection(SelectedVideoQualities selectedQualities,
413                 ListPreference preference) {
414             if (selectedQualities == null) {
415                 return;
416             }
417 
418             int selectedQuality = selectedQualities.getFromSetting(preference.getValue());
419             preference.setSummary(mCamcorderProfileNames[selectedQuality]);
420         }
421 
422         /**
423          * This method gets the selected picture sizes for S,M,L and populates
424          * {@link #mPictureSizesBack}, {@link #mPictureSizesFront},
425          * {@link #mVideoQualitiesBack} and {@link #mVideoQualitiesFront}
426          * accordingly.
427          */
loadSizes()428         private void loadSizes() {
429             if (mInfos == null) {
430                 Log.w(TAG, "null deviceInfo, cannot display resolution sizes");
431                 return;
432             }
433             // Back camera.
434             int backCameraId = SettingsUtil.getCameraId(mInfos, SettingsUtil.CAMERA_FACING_BACK);
435             if (backCameraId >= 0) {
436                 List<Size> sizes = CameraPictureSizesCacher.getSizesForCamera(backCameraId,
437                         this.getActivity().getApplicationContext());
438                 if (sizes != null) {
439                     mOldPictureSizesBack = SettingsUtil.getSelectedCameraPictureSizes(sizes,
440                             backCameraId);
441                     mPictureSizesBack = ResolutionUtil
442                             .getDisplayableSizesFromSupported(sizes, true);
443                 }
444                 mVideoQualitiesBack = SettingsUtil.getSelectedVideoQualities(backCameraId);
445             } else {
446                 mPictureSizesBack = null;
447                 mVideoQualitiesBack = null;
448             }
449 
450             // Front camera.
451             int frontCameraId = SettingsUtil.getCameraId(mInfos, SettingsUtil.CAMERA_FACING_FRONT);
452             if (frontCameraId >= 0) {
453                 List<Size> sizes = CameraPictureSizesCacher.getSizesForCamera(frontCameraId,
454                         this.getActivity().getApplicationContext());
455                 if (sizes != null) {
456                     mOldPictureSizesFront= SettingsUtil.getSelectedCameraPictureSizes(sizes,
457                             frontCameraId);
458                     mPictureSizesFront =
459                             ResolutionUtil.getDisplayableSizesFromSupported(sizes, false);
460                 }
461                 mVideoQualitiesFront = SettingsUtil.getSelectedVideoQualities(frontCameraId);
462             } else {
463                 mPictureSizesFront = null;
464                 mVideoQualitiesFront = null;
465             }
466         }
467 
468         /**
469          * @param size The photo resolution.
470          * @return A human readable and translated string for labeling the
471          *         picture size in megapixels.
472          */
getSizeSummaryString(Size size)473         private String getSizeSummaryString(Size size) {
474             Size approximateSize = ResolutionUtil.getApproximateSize(size);
475             String megaPixels = sMegaPixelFormat.format((size.width() * size.height()) / 1e6);
476             int numerator = ResolutionUtil.aspectRatioNumerator(approximateSize);
477             int denominator = ResolutionUtil.aspectRatioDenominator(approximateSize);
478             String result = getResources().getString(
479                     R.string.setting_summary_aspect_ratio_and_megapixels, numerator, denominator,
480                     megaPixels);
481             return result;
482         }
483     }
484 }
485