Home | History | Annotate | Download | only in settings
      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
     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
     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
    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
    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          */
    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
    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 
    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          */
    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          */
    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          */
    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
    282         public void onPause() {
    283             super.onPause();
    284             getPreferenceScreen().getSharedPreferences()
    285                     .unregisterOnSharedPreferenceChangeListener(this);
    286         }
    287 
    288         @Override
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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