diff options
34 files changed, 660 insertions, 233 deletions
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 654ee68..b8ba3f6 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -389,9 +389,10 @@ int get_size(const char *pkgname, const char *apkpath, int cachesize = 0; /* count the source apk as code -- but only if it's not - * on the /system partition + * on the /system partition and its not on the sdcard. */ - if (strncmp(apkpath, "/system", 7) != 0) { + if (strncmp(apkpath, "/system", 7) != 0 && + strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) { if (stat(apkpath, &s) == 0) { codesize += stat_size(&s); } @@ -403,17 +404,6 @@ int get_size(const char *pkgname, const char *apkpath, codesize += stat_size(&s); } } - - /* count the source apk as code -- but only if it's not - * installed on the sdcard - */ - if (strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) { - if (stat(apkpath, &s) == 0) { - codesize += stat_size(&s); - } - } - - /* count the cached dexfile as code */ if (!create_cache_path(path, apkpath)) { if (stat(path, &s) == 0) { diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h index 8330f8e..141f69b 100644 --- a/cmds/keystore/keystore_get.h +++ b/cmds/keystore/keystore_get.h @@ -32,9 +32,11 @@ extern "C" { #endif /* This function is provided for native components to get values from keystore. - * Users are required to link against libcutils. The lengths of keys and values - * are limited to KEYSTORE_MESSAGE_SIZE. This function returns the length of - * the requested value or -1 if something goes wrong. */ + * Users are required to link against libcutils. Keys are values are 8-bit safe. + * The first two arguments are the key and its length. The third argument + * specifies the buffer to store the retrieved value, which must be an array of + * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or + * -1 if an error happens. */ static int keystore_get(const char *key, int length, char *value) { uint8_t bytes[2] = {length >> 8, length}; diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index ebc64d7..add99d7 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -483,7 +483,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS int textId = mSearchable.getSearchButtonText(); if (isBrowserSearch()){ iconLabel = getContext().getResources() - .getDrawable(com.android.internal.R.drawable.ic_btn_search_play); + .getDrawable(com.android.internal.R.drawable.ic_btn_search_go); } else if (textId != 0) { textLabel = mActivityContext.getResources().getString(textId); } else { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 271f477..e1fbe48 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -439,6 +439,15 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19; /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package couldn't be installed in the specified install + * location because the media is not available. + * @hide + */ + public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20; + + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was given a path that is not a file, or does not end with the expected @@ -586,6 +595,14 @@ public abstract class PackageManager { public static final int MOVE_FAILED_INVALID_LOCATION = -5; /** + * Error code that is passed to the {@link IPackageMoveObserver} by + * {@link #movePackage(android.net.Uri, IPackageMoveObserver)} + * if the specified package cannot be moved to the specified location. + * @hide + */ + public static final int MOVE_FAILED_INTERNAL_ERROR = -6; + + /** * Flag parameter for {@link #movePackage} to indicate that * the package should be moved to internal storage if its * been installed on external media. diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index d1d8b0a..afe4191 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -19,6 +19,7 @@ package android.os; import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; +import android.net.wifi.WifiConfiguration; /** * @hide @@ -166,7 +167,7 @@ interface INetworkManagementService /** * Start Wifi Access Point */ - void startAccessPoint(); + void startAccessPoint(in WifiConfiguration wifiConfig, String intf); /** * Stop Wifi Access Point diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 503d8b8d..66f340e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2502,6 +2502,27 @@ public final class Settings { public static final String WIFI_AP_ON = "wifi_ap_on"; /** + * AP SSID + * + * @hide + */ + public static final String WIFI_AP_SSID = "wifi_ap_ssid"; + + /** + * AP security + * + * @hide + */ + public static final String WIFI_AP_SECURITY = "wifi_ap_security"; + + /** + * AP passphrase + * + * @hide + */ + public static final String WIFI_AP_PASSWD = "wifi_ap_passwd"; + + /** * The acceptable packet loss percentage (range 0 - 100) before trying * another AP on the same network. */ diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 034a631..3a34fb4 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -3851,7 +3851,6 @@ public class WebView extends AbsoluteLayout || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { if (nativeFocusIsPlugin()) { mShiftIsPressed = false; - return true; } else if (commitCopy()) { return true; } diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 9537ba0..5482958 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -985,6 +985,11 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe /** {@inheritDoc} */ public void onFilterComplete(int count) { + updateDropDownForFilter(count); + + } + + private void updateDropDownForFilter(int count) { // Not attached to window, don't update drop-down if (getWindowVisibility() == View.GONE) return; @@ -1214,18 +1219,30 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe ViewGroup dropDownView; int otherHeights = 0; - if (mAdapter != null) { + final ListAdapter adapter = mAdapter; + if (adapter != null) { InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) { - int N = mAdapter.getCount(); - if (N > 20) N = 20; - CompletionInfo[] completions = new CompletionInfo[N]; - for (int i = 0; i < N; i++) { - Object item = mAdapter.getItem(i); - long id = mAdapter.getItemId(i); - completions[i] = new CompletionInfo(id, i, - convertSelectionToString(item)); + final int count = Math.min(adapter.getCount(), 20); + CompletionInfo[] completions = new CompletionInfo[count]; + int realCount = 0; + + for (int i = 0; i < count; i++) { + if (adapter.isEnabled(i)) { + realCount++; + Object item = adapter.getItem(i); + long id = adapter.getItemId(i); + completions[i] = new CompletionInfo(id, i, + convertSelectionToString(item)); + } } + + if (realCount != count) { + CompletionInfo[] tmp = new CompletionInfo[realCount]; + System.arraycopy(completions, 0, tmp, 0, realCount); + completions = tmp; + } + imm.displayCompletions(this, completions); } } @@ -1253,7 +1270,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe mDropDownList = new DropDownListView(context); mDropDownList.setSelector(mDropDownListHighlight); - mDropDownList.setAdapter(mAdapter); + mDropDownList.setAdapter(adapter); mDropDownList.setVerticalFadingEdgeEnabled(true); mDropDownList.setOnItemClickListener(mDropDownItemClickListener); mDropDownList.setFocusable(true); @@ -1599,6 +1616,16 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe if (isPopupShowing()) { // This will resize the popup to fit the new adapter's content showDropDown(); + } else if (mAdapter != null) { + // If the popup is not showing already, showing it will cause + // the list of data set observers attached to the adapter to + // change. We can't do it from here, because we are in the middle + // of iterating throught he list of observers. + post(new Runnable() { + public void run() { + updateDropDownForFilter(mAdapter.getCount()); + } + }); } } diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl index fd1fd58..badabb0 100755 --- a/core/java/com/android/internal/app/IMediaContainerService.aidl +++ b/core/java/com/android/internal/app/IMediaContainerService.aidl @@ -27,4 +27,5 @@ interface IMediaContainerService { boolean copyResource(in Uri packageURI, in ParcelFileDescriptor outStream); PackageInfoLite getMinimalPackageInfo(in Uri fileUri); + boolean checkFreeStorage(boolean external, in Uri fileUri); }
\ No newline at end of file diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 80efca4..4d0a9e0 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -38,6 +38,7 @@ public class PackageHelper { public static final int RECOMMEND_FAILED_INVALID_APK = -2; public static final int RECOMMEND_FAILED_INVALID_LOCATION = -3; public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4; + public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5; private static final boolean localLOGV = true; private static final String TAG = "PackageHelper"; // App installation location settings values @@ -70,7 +71,7 @@ public class PackageHelper { try { int rc = mountService.createSecureContainer( - cid, mbLen, "vfat", sdEncKey, uid); + cid, mbLen, "fat", sdEncKey, uid); if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to create secure container " + cid); return null; diff --git a/core/res/res/drawable-hdpi/ic_btn_search_go.png b/core/res/res/drawable-hdpi/ic_btn_search_go.png Binary files differnew file mode 100644 index 0000000..8a3a402 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_btn_search_go.png diff --git a/core/res/res/drawable-hdpi/ic_btn_search_play.png b/core/res/res/drawable-hdpi/ic_btn_search_play.png Binary files differdeleted file mode 100644 index fb1b974..0000000 --- a/core/res/res/drawable-hdpi/ic_btn_search_play.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/ic_btn_search_go.png b/core/res/res/drawable-mdpi/ic_btn_search_go.png Binary files differnew file mode 100644 index 0000000..0ed9e8e --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_btn_search_go.png diff --git a/core/res/res/drawable-mdpi/ic_btn_search_play.png b/core/res/res/drawable-mdpi/ic_btn_search_play.png Binary files differdeleted file mode 100644 index dc25dae..0000000 --- a/core/res/res/drawable-mdpi/ic_btn_search_play.png +++ /dev/null diff --git a/core/res/res/layout-land/usb_storage_activity.xml b/core/res/res/layout-land/usb_storage_activity.xml index d714479..50ca569 100644 --- a/core/res/res/layout-land/usb_storage_activity.xml +++ b/core/res/res/layout-land/usb_storage_activity.xml @@ -24,7 +24,7 @@ <TextView android:id="@+id/banner" android:layout_centerHorizontal="true" - android:layout_below="@id/icon" + android:layout_alignParentTop="true" android:layout_marginTop="10dip" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -45,8 +45,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" - android:layout_below="@id/message" - android:layout_marginTop="20dip" + android:layout_alignParentBottom="true" + android:layout_marginBottom="20dip" > <Button android:id="@+id/mount_button" @@ -64,6 +64,13 @@ android:paddingRight="18dip" android:text="@string/usb_storage_stop_button_mount" /> + <ProgressBar android:id="@+id/progress" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:indeterminate="true" + style="?android:attr/progressBarStyle" + /> </RelativeLayout> </RelativeLayout> diff --git a/core/res/res/layout/usb_storage_activity.xml b/core/res/res/layout/usb_storage_activity.xml index 86bfadb..76c30fd 100644 --- a/core/res/res/layout/usb_storage_activity.xml +++ b/core/res/res/layout/usb_storage_activity.xml @@ -37,8 +37,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" - android:layout_below="@id/message" - android:layout_marginTop="20dip" + android:layout_alignParentBottom="true" + android:layout_marginBottom="20dip" > <Button android:id="@+id/mount_button" @@ -56,6 +56,13 @@ android:paddingRight="18dip" android:text="@string/usb_storage_stop_button_mount" /> + <ProgressBar android:id="@+id/progress" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:indeterminate="true" + style="?android:attr/progressBarStyle" + /> </RelativeLayout> </RelativeLayout> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 584fe25..bf7425f 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2013,6 +2013,8 @@ <item quantity="one">Open Wi-Fi network available</item> <item quantity="other">Open Wi-Fi networks available</item> </plurals> + <!-- Do not translate. Default access point SSID used for tethering --> + <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string> <!-- Name of the dialog that lets the user choose an accented character to insert --> <string name="select_character">Insert character</string> diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 7902212..815a367 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -72,6 +72,10 @@ static const float MAX_GAIN = 4096.0f; // 50 * ~20msecs = 1 second static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; +// allow less retry attempts on direct output thread. +// direct outputs can be a scarce resource in audio hardware and should +// be released as quickly as possible. +static const int8_t kMaxTrackRetriesDirect = 2; static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 20000; @@ -1794,6 +1798,9 @@ bool AudioFlinger::DirectOutputThread::threadLoop() uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; + // use shorter standby delay as on normal output to release + // hardware resources as soon as possible + nsecs_t standbyDelay = microseconds(activeSleepTime*2); while (!exitPending()) @@ -1810,6 +1817,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() mixBufferSize = mFrameCount*mFrameSize; activeSleepTime = activeSleepTimeUs(); idleSleepTime = idleSleepTimeUs(); + standbyDelay = microseconds(activeSleepTime*2); } // put audio hardware into standby after short delay @@ -1842,7 +1850,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + standbyDelay; sleepTime = idleSleepTime; continue; } @@ -1896,7 +1904,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } // reset retry count - track->mRetryCount = kMaxTrackRetries; + track->mRetryCount = kMaxTrackRetriesDirect; activeTrack = t; mixerStatus = MIXER_TRACKS_READY; } else { @@ -1949,7 +1957,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() activeTrack->releaseBuffer(&buffer); } sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + standbyDelay; } else { if (sleepTime == 0) { if (mixerStatus == MIXER_TRACKS_ENABLED) { diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp index a61221a..c8b3f48 100644 --- a/libs/audioflinger/AudioPolicyManagerBase.cpp +++ b/libs/audioflinger/AudioPolicyManagerBase.cpp @@ -458,11 +458,8 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str } #endif //AUDIO_POLICY_TEST - // open a direct output if: - // 1 a direct output is explicitely requested - // 2 the audio format is compressed - if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || - (format !=0 && !AudioSystem::isLinearPCM(format))) { + // open a direct output if required by specified parameters + if (needsDirectOuput(stream, samplingRate, format, channels, flags, device)) { LOGV("getOutput() opening direct output device %x", device); AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); @@ -472,7 +469,7 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str outputDesc->mChannels = channels; outputDesc->mLatency = 0; outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT); - outputDesc->mRefCount[stream] = 1; + outputDesc->mRefCount[stream] = 0; output = mpClientInterface->openOutput(&outputDesc->mDevice, &outputDesc->mSamplingRate, &outputDesc->mFormat, @@ -609,6 +606,9 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSyste setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2); } #endif + if (output != mHardwareOutput) { + setOutputDevice(mHardwareOutput, getNewDevice(mHardwareOutput), true); + } return NO_ERROR; } else { LOGW("stopOutput() refcount is already 0 for output %d", output); @@ -1550,10 +1550,10 @@ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t } #ifdef WITH_A2DP // filter devices according to output selected - if (output == mHardwareOutput) { - device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; - } else { + if (output == mA2dpOutput) { device &= AudioSystem::DEVICE_OUT_ALL_A2DP; + } else { + device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; } #endif @@ -1562,8 +1562,7 @@ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t // - the requestede device is 0 // - the requested device is the same as current device and force is not specified. // Doing this check here allows the caller to call setOutputDevice() without conditions - if (device == 0 || - (device == prevDevice && !force)) { + if ((device == 0 || device == prevDevice) && !force) { LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output); return; } @@ -1666,7 +1665,7 @@ float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_hand int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); volume = AudioSystem::linearToLog(volInt); - // if a heaset is connected, apply the following rules to ring tones and notifications + // if a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: // - always attenuate ring tones and notifications volume by 6dB // - if music is playing, always limit the volume to current music volume, @@ -1825,6 +1824,17 @@ void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, } } +bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::output_flags flags, + uint32_t device) +{ + return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || + (format !=0 && !AudioSystem::isLinearPCM(format))); +} + // --- AudioOutputDescriptor class implementation AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor() diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index 140f10c..efbc77a 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -214,7 +214,6 @@ uint32_t LayerBase::doTransaction(uint32_t flags) if ((front.w != temp.w) || (front.h != temp.h)) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; - this->contentDirty = true; } if (temp.sequence != front.sequence) { diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index a6e5644..62ec839 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -157,11 +157,11 @@ public: /** * setCoveredRegion - called when the covered region changes. The covered - * region correspond to any area of the surface that is covered + * region corresponds to any area of the surface that is covered * (transparently or not) by another surface. */ virtual void setCoveredRegion(const Region& coveredRegion); - + /** * validateVisibility - cache a bunch of things */ diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 26ee285..0722fda 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -674,6 +674,8 @@ void SurfaceFlinger::computeVisibleRegions( { const GraphicPlane& plane(graphicPlane(0)); const Transform& planeTransform(plane.transform()); + const DisplayHardware& hw(plane.displayHardware()); + const Region screenRegion(hw.bounds()); Region aboveOpaqueLayers; Region aboveCoveredLayers; @@ -689,31 +691,56 @@ void SurfaceFlinger::computeVisibleRegions( // start with the whole surface at its current location const Layer::State& s(layer->drawingState()); - // handle hidden surfaces by setting the visible region to empty + /* + * opaqueRegion: area of a surface that is fully opaque. + */ Region opaqueRegion; + + /* + * visibleRegion: area of a surface that is visible on screen + * and not fully transparent. This is essentially the layer's + * footprint minus the opaque regions above it. + * Areas covered by a translucent surface are considered visible. + */ Region visibleRegion; + + /* + * coveredRegion: area of a surface that is covered by all + * visible regions above it (which includes the translucent areas). + */ Region coveredRegion; + + + // handle hidden surfaces by setting the visible region to empty if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { const bool translucent = layer->needsBlending(); const Rect bounds(layer->visibleBounds()); visibleRegion.set(bounds); - coveredRegion = visibleRegion; - - // Remove the transparent area from the visible region - if (translucent) { - visibleRegion.subtractSelf(layer->transparentRegionScreen); - } + visibleRegion.andSelf(screenRegion); + if (!visibleRegion.isEmpty()) { + // Remove the transparent area from the visible region + if (translucent) { + visibleRegion.subtractSelf(layer->transparentRegionScreen); + } - // compute the opaque region - if (s.alpha==255 && !translucent && layer->getOrientation()>=0) { - // the opaque region is the visible region - opaqueRegion = visibleRegion; + // compute the opaque region + const int32_t layerOrientation = layer->getOrientation(); + if (s.alpha==255 && !translucent && + ((layerOrientation & Transform::ROT_INVALID) == false)) { + // the opaque region is the layer's footprint + opaqueRegion = visibleRegion; + } } } + // Clip the covered region to the visible region + coveredRegion = aboveCoveredLayers.intersect(visibleRegion); + + // Update aboveCoveredLayers for next (lower) layer + aboveCoveredLayers.orSelf(visibleRegion); + // subtract the opaque region covered by the layers above us visibleRegion.subtractSelf(aboveOpaqueLayers); - coveredRegion.andSelf(aboveCoveredLayers); // compute this layer's dirty region if (layer->contentDirty) { @@ -724,19 +751,30 @@ void SurfaceFlinger::computeVisibleRegions( layer->contentDirty = false; } else { /* compute the exposed region: - * exposed = what's VISIBLE and NOT COVERED now - * but was COVERED before + * the exposed region consists of two components: + * 1) what's VISIBLE now and was COVERED before + * 2) what's EXPOSED now less what was EXPOSED before + * + * note that (1) is conservative, we start with the whole + * visible region but only keep what used to be covered by + * something -- which mean it may have been exposed. + * + * (2) handles areas that were not covered by anything but got + * exposed because of a resize. */ - dirty = (visibleRegion - coveredRegion) & layer->coveredRegionScreen; + const Region newExposed = visibleRegion - coveredRegion; + const Region oldVisibleRegion = layer->visibleRegionScreen; + const Region oldCoveredRegion = layer->coveredRegionScreen; + const Region oldExposed = oldVisibleRegion - oldCoveredRegion; + dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } dirty.subtractSelf(aboveOpaqueLayers); // accumulate to the screen dirty region dirtyRegion.orSelf(dirty); - // Update aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer + // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); - aboveCoveredLayers.orSelf(visibleRegion); // Store the visible region is screen space layer->setVisibleRegion(visibleRegion); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 4b364f2..5e6ce42 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -358,7 +358,7 @@ unsigned int AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); unsigned int result = 0; if (af == 0) return result; - if (ioHandle == NULL) return result; + if (ioHandle == 0) return result; result = af->getInputFramesLost(ioHandle); return result; @@ -556,7 +556,18 @@ audio_io_handle_t AudioSystem::getOutput(stream_type stream, output_flags flags) { audio_io_handle_t output = 0; - if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) { + // Do not use stream to output map cache if the direct output + // flag is set or if we are likely to use a direct output + // (e.g voice call stream @ 8kHz could use BT SCO device and be routed to + // a direct output on some platforms). + // TODO: the output cache and stream to output mapping implementation needs to + // be reworked for proper operation with direct outputs. This code is too specific + // to the first use case we want to cover (Voice Recognition and Voice Dialer over + // Bluetooth SCO + if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0 && + ((stream != AudioSystem::VOICE_CALL && stream != AudioSystem::BLUETOOTH_SCO) || + channels != AudioSystem::CHANNEL_OUT_MONO || + (samplingRate != 8000 && samplingRate != 16000))) { Mutex::Autolock _l(gLock); output = AudioSystem::gStreamOutputMap.valueFor(stream); LOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream); diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index c6b617d..77d11cc 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -24,7 +24,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.net.Uri; import android.os.Environment; import android.os.IBinder; @@ -45,7 +44,6 @@ import java.io.IOException; import java.io.InputStream; import android.os.FileUtils; -import android.os.storage.IMountService; import android.provider.Settings; /* @@ -130,26 +128,21 @@ public class DefaultContainerService extends IntentService { ret.packageName = pkg.packageName; ret.installLocation = pkg.installLocation; // Nuke the parser reference right away and force a gc - Runtime.getRuntime().gc(); packageParser = null; + Runtime.getRuntime().gc(); if (pkg == null) { Log.w(TAG, "Failed to parse package"); ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; return ret; } ret.packageName = pkg.packageName; - int loc = recommendAppInstallLocation(pkg.installLocation, archiveFilePath); - if (loc == PackageManager.INSTALL_EXTERNAL) { - ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_EXTERNAL; - } else if (loc == ERR_LOC) { - Log.i(TAG, "Failed to install insufficient storage"); - ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; - } else { - // Implies install on internal storage. - ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } + ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath); return ret; } + + public boolean checkFreeStorage(boolean external, Uri fileUri) { + return checkFreeStorageInner(external, fileUri); + } }; public DefaultContainerService() { @@ -190,6 +183,12 @@ public class DefaultContainerService extends IntentService { } private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName) { + // Make sure the sdcard is mounted. + String status = Environment.getExternalStorageState(); + if (!status.equals(Environment.MEDIA_MOUNTED)) { + Log.w(TAG, "Make sure sdcard is mounted."); + return null; + } // Create new container at newCachePath String codePath = packageURI.getPath(); File codeFile = new File(codePath); @@ -313,11 +312,13 @@ public class DefaultContainerService extends IntentService { // Else install on internal NAND flash, unless space on NAND is less than 10% String status = Environment.getExternalStorageState(); long availSDSize = -1; + boolean mediaAvailable = false; if (status.equals(Environment.MEDIA_MOUNTED)) { StatFs sdStats = new StatFs( Environment.getExternalStorageDirectory().getPath()); availSDSize = (long)sdStats.getAvailableBlocks() * (long)sdStats.getBlockSize(); + mediaAvailable = true; } StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); long totalInternalSize = (long)internalStats.getBlockCount() * @@ -337,7 +338,8 @@ public class DefaultContainerService extends IntentService { long reqInternalSize = 0; boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); - boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk && + boolean fitsOnSd = mediaAvailable && (reqInstallSize < availSDSize) + && intThresholdOk && (reqInternalSize < availInternalSize); boolean fitsOnInt = intThresholdOk && intAvailOk; @@ -377,21 +379,58 @@ public class DefaultContainerService extends IntentService { } if (!auto) { if (installOnlyOnSd) { - return fitsOnSd ? PackageManager.INSTALL_EXTERNAL : ERR_LOC; + if (fitsOnSd) { + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + } + if (!mediaAvailable) { + return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; + } + return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } else if (installOnlyInternal){ // Check on internal flash - return fitsOnInt ? 0 : ERR_LOC; + return fitsOnInt ? PackageHelper.RECOMMEND_INSTALL_INTERNAL : + PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } } // Try to install internally if (fitsOnInt) { - return 0; + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } // Try the sdcard now. if (fitsOnSd) { - return PackageManager.INSTALL_EXTERNAL; + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } // Return error code - return ERR_LOC; + return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; + } + + private boolean checkFreeStorageInner(boolean external, Uri packageURI) { + File apkFile = new File(packageURI.getPath()); + long size = apkFile.length(); + if (external) { + String status = Environment.getExternalStorageState(); + long availSDSize = -1; + if (status.equals(Environment.MEDIA_MOUNTED)) { + StatFs sdStats = new StatFs( + Environment.getExternalStorageDirectory().getPath()); + availSDSize = (long)sdStats.getAvailableBlocks() * + (long)sdStats.getBlockSize(); + } + return availSDSize > size; + } + StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); + long totalInternalSize = (long)internalStats.getBlockCount() * + (long)internalStats.getBlockSize(); + long availInternalSize = (long)internalStats.getAvailableBlocks() * + (long)internalStats.getBlockSize(); + + double pctNandFree = (double)availInternalSize / (double)totalInternalSize; + // To make final copy + long reqInstallSize = size; + // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. + long reqInternalSize = 0; + boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); + boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); + return intThresholdOk && intAvailOk; } } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index b8b94a1..d50f591 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -51,6 +51,8 @@ import java.util.HashSet; class MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks { private static final boolean LOCAL_LOGD = false; + private static final boolean DEBUG_UNMOUNT = false; + private static final boolean DEBUG_EVENTS = false; private static final String TAG = "MountService"; @@ -156,6 +158,7 @@ class MountService extends IMountService.Stub } void handleFinished() { + if (DEBUG_UNMOUNT) Log.i(TAG, "Unmounting " + path); doUnmountVolume(path, true); } } @@ -205,22 +208,27 @@ class MountService extends IMountService.Stub void registerReceiver() { mRegistered = true; + if (DEBUG_UNMOUNT) Log.i(TAG, "Registering receiver"); mContext.registerReceiver(mPmReceiver, mPmFilter); } void unregisterReceiver() { mRegistered = false; + if (DEBUG_UNMOUNT) Log.i(TAG, "Unregistering receiver"); mContext.unregisterReceiver(mPmReceiver); } public void handleMessage(Message msg) { switch (msg.what) { case H_UNMOUNT_PM_UPDATE: { + if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_UPDATE"); UnmountCallBack ucb = (UnmountCallBack) msg.obj; mForceUnmounts.add(ucb); + if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mRegistered); // Register only if needed. if (!mRegistered) { registerReceiver(); + if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status"); boolean hasExtPkgs = mPms.updateExternalMediaStatus(false); if (!hasExtPkgs) { // Unregister right away @@ -230,6 +238,7 @@ class MountService extends IMountService.Stub break; } case H_UNMOUNT_PM_DONE: { + if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_DONE"); // Unregister now. if (mRegistered) { unregisterReceiver(); @@ -286,6 +295,7 @@ class MountService extends IMountService.Stub break; } case H_UNMOUNT_MS : { + if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_MS"); UnmountCallBack ucb = (UnmountCallBack) msg.obj; ucb.handleFinished(); break; @@ -393,7 +403,12 @@ class MountService extends IMountService.Stub Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state)); return; } - + // Update state on PackageManager + if (Environment.MEDIA_UNMOUNTED.equals(state)) { + mPms.updateExternalMediaStatus(false); + } else if (Environment.MEDIA_MOUNTED.equals(state)) { + mPms.updateExternalMediaStatus(true); + } String oldState = mLegacyState; mLegacyState = state; @@ -456,6 +471,7 @@ class MountService extends IMountService.Stub } } if (state != null) { + if (DEBUG_EVENTS) Log.i(TAG, "Updating valid state " + state); updatePublicVolumeState(path, state); } } catch (Exception e) { @@ -484,6 +500,18 @@ class MountService extends IMountService.Stub public boolean onEvent(int code, String raw, String[] cooked) { Intent in = null; + if (DEBUG_EVENTS) { + StringBuilder builder = new StringBuilder(); + builder.append("onEvent::"); + builder.append(" raw= " + raw); + if (cooked != null) { + builder.append(" cooked = " ); + for (String str : cooked) { + builder.append(" " + str); + } + } + Log.i(TAG, builder.toString()); + } if (code == VoldResponseCode.VolumeStateChange) { /* * One of the volumes we're managing has changed state. @@ -541,18 +569,22 @@ class MountService extends IMountService.Stub return true; } /* Send the media unmounted event first */ + if (DEBUG_EVENTS) Log.i(TAG, "Sending unmounted event first"); updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); mContext.sendBroadcast(in); + if (DEBUG_EVENTS) Log.i(TAG, "Sending media removed"); updatePublicVolumeState(path, Environment.MEDIA_REMOVED); in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path)); } else if (code == VoldResponseCode.VolumeBadRemoval) { + if (DEBUG_EVENTS) Log.i(TAG, "Sending unmounted event first"); /* Send the media unmounted event first */ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); mContext.sendBroadcast(in); + if (DEBUG_EVENTS) Log.i(TAG, "Sending media bad removal"); updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path)); } else { @@ -570,6 +602,7 @@ class MountService extends IMountService.Stub private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { String vs = getVolumeState(path); + if (DEBUG_EVENTS) Log.i(TAG, "notifyVolumeStateChanged::" + vs); Intent in = null; @@ -591,29 +624,31 @@ class MountService extends IMountService.Stub Environment.MEDIA_BAD_REMOVAL) && !vs.equals( Environment.MEDIA_NOFS) && !vs.equals( Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { + if (DEBUG_EVENTS) Log.i(TAG, "updating volume state for media bad removal nofs and unmountable"); updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); } } else if (newState == VolumeState.Pending) { } else if (newState == VolumeState.Checking) { + if (DEBUG_EVENTS) Log.i(TAG, "updating volume state checking"); updatePublicVolumeState(path, Environment.MEDIA_CHECKING); in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path)); } else if (newState == VolumeState.Mounted) { + if (DEBUG_EVENTS) Log.i(TAG, "updating volume state mounted"); updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); - // Update media status on PackageManagerService to mount packages on sdcard - mPms.updateExternalMediaStatus(true); in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path)); in.putExtra("read-only", false); } else if (newState == VolumeState.Unmounting) { - mPms.updateExternalMediaStatus(false); in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path)); } else if (newState == VolumeState.Formatting) { } else if (newState == VolumeState.Shared) { + if (DEBUG_EVENTS) Log.i(TAG, "Updating volume state media mounted"); /* Send the media unmounted event first */ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); mContext.sendBroadcast(in); + if (DEBUG_EVENTS) Log.i(TAG, "Updating media shared"); updatePublicVolumeState(path, Environment.MEDIA_SHARED); in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path)); if (LOCAL_LOGD) Log.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); @@ -657,6 +692,7 @@ class MountService extends IMountService.Stub private int doMountVolume(String path) { int rc = StorageResultCode.OperationSucceeded; + if (DEBUG_EVENTS) Log.i(TAG, "doMountVolume: Mouting " + path); try { mConnector.doCommand(String.format("volume mount %s", path)); } catch (NativeDaemonConnectorException e) { @@ -671,6 +707,7 @@ class MountService extends IMountService.Stub */ rc = StorageResultCode.OperationFailedNoMedia; } else if (code == VoldResponseCode.OpFailedMediaBlank) { + if (DEBUG_EVENTS) Log.i(TAG, " updating volume state :: media nofs"); /* * Media is blank or does not contain a supported filesystem */ @@ -678,6 +715,7 @@ class MountService extends IMountService.Stub in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); rc = StorageResultCode.OperationFailedMediaBlank; } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { + if (DEBUG_EVENTS) Log.i(TAG, "updating volume state media corrupt"); /* * Volume consistency check failed */ @@ -1040,6 +1078,16 @@ class MountService extends IMountService.Stub validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); waitForReady(); + String volState = getVolumeState(path); + if (DEBUG_UNMOUNT) Log.i(TAG, "Unmounting " + path + " force = " + force); + if (Environment.MEDIA_UNMOUNTED.equals(volState) || + Environment.MEDIA_REMOVED.equals(volState) || + Environment.MEDIA_SHARED.equals(volState) || + Environment.MEDIA_UNMOUNTABLE.equals(volState)) { + // Media already unmounted or cannot be unmounted. + // TODO return valid return code when adding observer call back. + return; + } UnmountCallBack ucb = new UnmountCallBack(path, force); mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index aa9ced8..b114ca2 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -26,10 +26,13 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.os.INetworkManagementService; import android.os.Handler; import android.os.SystemProperties; import android.text.TextUtils; +import android.util.Log; import android.util.Slog; import java.util.ArrayList; import java.util.StringTokenizer; @@ -457,14 +460,38 @@ class NetworkManagementService extends INetworkManagementService.Stub { throw new IllegalStateException("Got an empty response"); } - public void startAccessPoint() + public void startAccessPoint(WifiConfiguration wifiConfig, String intf) throws IllegalStateException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); - mConnector.doCommand(String.format("softap set")); - mConnector.doCommand(String.format("softap start")); + mConnector.doCommand(String.format("softap stop " + intf)); + mConnector.doCommand(String.format("softap fwreload " + intf + " AP")); + mConnector.doCommand(String.format("softap start " + intf)); + if (wifiConfig == null) { + mConnector.doCommand(String.format("softap set " + intf + " wl0.1")); + } else { + /** + * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8] + * argv1 - wlan interface + * argv2 - softap interface + * argv3 - SSID + * argv4 - Security + * argv5 - Key + * argv6 - Channel + * argv7 - Preamble + * argv8 - Max SCB + * + * TODO: get a configurable softap interface from driver + */ + String str = String.format("softap set " + intf + " wl0.1 %s %s %s", wifiConfig.SSID, + wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? + "wpa2-psk" : "open", + wifiConfig.preSharedKey); + mConnector.doCommand(str); + } + mConnector.doCommand(String.format("softap startap")); } public void stopAccessPoint() throws IllegalStateException { @@ -472,7 +499,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); - mConnector.doCommand("softap stop"); + mConnector.doCommand("softap stopap"); } } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 139c05f..818e99e 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -4613,6 +4613,12 @@ class PackageManagerService extends IPackageManager.Stub { return pkgLite.recommendedInstallLocation; } + /* + * Invoke remote method to get package information and install + * location values. Override install location based on default + * policy if needed and then create install arguments based + * on the install location. + */ public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; @@ -4624,9 +4630,7 @@ class PackageManagerService extends IPackageManager.Stub { } else { // Remote call to find out default install location PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(packageURI); - int loc = installLocationPolicy(pkgLite, flags); - // Use install location to create InstallArgs and temporary - // install location + int loc = pkgLite.recommendedInstallLocation; if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS){ @@ -4635,7 +4639,11 @@ class PackageManagerService extends IPackageManager.Stub { ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { ret = PackageManager.INSTALL_FAILED_INVALID_APK; + } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { + ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; } else { + // Override with defaults if needed. + loc = installLocationPolicy(pkgLite, flags); // Override install location with flags if ((flags & PackageManager.INSTALL_EXTERNAL) == 0){ if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { @@ -4701,6 +4709,12 @@ class PackageManagerService extends IPackageManager.Stub { } public void handleStartCopy() throws RemoteException { + mRet = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + // Check for storage space on target medium + if (!targetArgs.checkFreeStorage(mContainerService)) { + Log.w(TAG, "Insufficient storage to install"); + return; + } // Create the file args now. mRet = targetArgs.copyApk(mContainerService, false); targetArgs.doPreInstall(mRet); @@ -4714,15 +4728,20 @@ class PackageManagerService extends IPackageManager.Stub { builder.append(" target : "); builder.append(targetArgs.getCodePath()); } - Log.i(TAG, "Posting move MCS_UNBIND for " + builder.toString()); + Log.i(TAG, builder.toString()); } } @Override void handleReturnCode() { targetArgs.doPostInstall(mRet); - // TODO invoke pending move - processPendingMove(this, mRet); + int currentStatus = PackageManager.MOVE_FAILED_INTERNAL_ERROR; + if (mRet == PackageManager.INSTALL_SUCCEEDED) { + currentStatus = PackageManager.MOVE_SUCCEEDED; + } else if (mRet == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){ + currentStatus = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE; + } + processPendingMove(this, currentStatus); } @Override @@ -4782,6 +4801,7 @@ class PackageManagerService extends IPackageManager.Stub { // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); abstract boolean doPostDeleteLI(boolean delete); + abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException; } class FileInstallArgs extends InstallArgs { @@ -4812,6 +4832,10 @@ class PackageManagerService extends IPackageManager.Stub { resourceFileName = getResourcePathFromCodePath(); } + boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { + return imcs.checkFreeStorage(false, packageURI); + } + String getCodePath() { return codeFileName; } @@ -5013,6 +5037,10 @@ class PackageManagerService extends IPackageManager.Stub { cid = getTempContainerId(); } + boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { + return imcs.checkFreeStorage(true, packageURI); + } + int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { if (temp) { createCopyFile(); @@ -9109,6 +9137,9 @@ class PackageManagerService extends IPackageManager.Stub { public boolean updateExternalMediaStatus(final boolean mediaStatus) { final boolean ret; synchronized (mPackages) { + Log.i(TAG, "Updating external media status from " + + (mMediaMounted ? "mounted" : "unmounted") + " to " + + (mediaStatus ? "mounted" : "unmounted")); if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus+", mMediaMounted=" + mMediaMounted); if (mediaStatus == mMediaMounted) { @@ -9117,6 +9148,14 @@ class PackageManagerService extends IPackageManager.Stub { mMediaMounted = mediaStatus; Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE); ret = appList != null && appList.size() > 0; + if (DEBUG_SD_INSTALL) { + if (appList != null) { + for (String app : appList) { + Log.i(TAG, "Should enable " + app + " on sdcard"); + } + } + } + if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus returning " + ret); } // Queue up an async operation since the package installation may take a little while. mHandler.post(new Runnable() { @@ -9134,6 +9173,7 @@ class PackageManagerService extends IPackageManager.Stub { // enabled or disabled. final String list[] = PackageHelper.getSecureContainerList(); if (list == null || list.length == 0) { + Log.i(TAG, "No secure containers on sdcard"); return; } @@ -9141,16 +9181,6 @@ class PackageManagerService extends IPackageManager.Stub { int num = 0; HashSet<String> removeCids = new HashSet<String>(); HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>(); - /*HashMap<String, String> cidPathMap = new HashMap<String, String>(); - // Don't hold any locks when getting cache paths - for (String cid : list) { - String cpath = PackageHelper.getSdDir(cid); - if (cpath == null) { - removeCids.add(cid); - } else { - cidPathMap.put(cid, cpath); - } - }*/ synchronized (mPackages) { for (String cid : list) { SdInstallArgs args = new SdInstallArgs(cid); diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index 37a3cdf..5bd23f4 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -20,7 +20,6 @@ import android.app.Activity; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.IActivityManager; -import android.app.KeyguardManager; import android.app.IUiModeManager; import android.app.Notification; import android.app.NotificationManager; @@ -103,7 +102,6 @@ class UiModeManagerService extends IUiModeManager.Stub { private LocationManager mLocationManager; private Location mLocation; private StatusBarManager mStatusBarManager; - private KeyguardManager.KeyguardLock mKeyguardLock; private final PowerManager.WakeLock mWakeLock; // The broadcast receiver which receives the result of the ordered broadcast sent when @@ -347,24 +345,6 @@ class UiModeManagerService extends IUiModeManager.Stub { void setCarModeLocked(boolean enabled) { if (mCarModeEnabled != enabled) { mCarModeEnabled = enabled; - - // Disable keyguard when in car mode - if (mKeyguardLock == null) { - KeyguardManager km = - (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); - if (km != null) { - mKeyguardLock = km.newKeyguardLock(TAG); - } - } - if (mKeyguardLock != null) { - long ident = Binder.clearCallingIdentity(); - if (enabled) { - mKeyguardLock.disableKeyguard(); - } else { - mKeyguardLock.reenableKeyguard(); - } - Binder.restoreCallingIdentity(ident); - } } } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 599eec5..4eb529c 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -46,6 +46,7 @@ import android.net.wifi.WifiStateTracker; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.SupplicantState; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.ConnectivityManager; import android.net.InterfaceConfiguration; import android.net.NetworkStateTracker; @@ -81,6 +82,7 @@ import java.net.UnknownHostException; import com.android.internal.app.IBatteryStats; import android.app.backup.IBackupManager; import com.android.server.am.BatteryStatsService; +import com.android.internal.R; /** * WifiService handles remote WiFi operation requests by implementing @@ -105,6 +107,8 @@ public class WifiService extends IWifiManager.Stub { private boolean mDeviceIdle; private int mPluggedType; + private enum DriverAction {DRIVER_UNLOAD, NO_DRIVER_UNLOAD}; + // true if the user enabled Wifi while in airplane mode private boolean mAirplaneModeOverwridden; @@ -271,11 +275,9 @@ public class WifiService extends IWifiManager.Stub { */ public void startWifi() { boolean wifiEnabled = getPersistedWifiEnabled(); - boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled(); Slog.i(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); setWifiEnabledBlocking(wifiEnabled, false, Process.myUid()); - setWifiApEnabledBlocking(wifiAPEnabled, true, Process.myUid(), null); } private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) { @@ -297,28 +299,22 @@ public class WifiService extends IWifiManager.Stub { try { ifcg = service.getInterfaceConfig(intf); if (ifcg != null) { - /* IP/netmask: 169.254.2.1/255.255.255.0 */ - ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1; + /* IP/netmask: 169.254.2.2/255.255.255.0 */ + ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 2; ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0; ifcg.interfaceFlags = "up"; service.setInterfaceConfig(intf, ifcg); } } catch (Exception e) { - /** - * TODO: Add broadcast to indicate tether failed - */ Slog.e(TAG, "Error configuring interface " + intf + ", :" + e); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD); return; } - /** - * TODO: Add broadcast to indicate tether failed - */ - if(mCm.tether(intf) == ConnectivityManager.TETHER_ERROR_NO_ERROR) { - Slog.d(TAG, "Tethered "+intf); - } else { + if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { Slog.e(TAG, "Error tethering "+intf); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD); } break; } @@ -434,7 +430,7 @@ public class WifiService extends IWifiManager.Stub { setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid); if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) { - setWifiApEnabledBlocking(false, true, Process.myUid(), null); + setWifiApEnabledBlocking(false, Process.myUid(), null); } if (enable) { @@ -581,21 +577,6 @@ public class WifiService extends IWifiManager.Stub { return mWifiStateTracker.reassociate(); } - private boolean getPersistedWifiApEnabled() { - final ContentResolver cr = mContext.getContentResolver(); - try { - return Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_ON) == 1; - } catch (Settings.SettingNotFoundException e) { - Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_ON, 0); - return false; - } - } - - private void persistWifiApEnabled(boolean enabled) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_ON, enabled ? 1 : 0); - } - /** * see {@link android.net.wifi.WifiManager#startAccessPoint(WifiConfiguration)} * @param wifiConfig SSID, security and channel details as @@ -621,46 +602,101 @@ public class WifiService extends IWifiManager.Stub { return true; } + public WifiConfiguration getWifiApConfiguration() { + final ContentResolver cr = mContext.getContentResolver(); + WifiConfiguration wifiConfig = new WifiConfiguration(); + int authType; + try { + wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID); + if (wifiConfig.SSID == null) + return null; + authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY); + wifiConfig.allowedKeyManagement.set(authType); + wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD); + return wifiConfig; + } catch (Settings.SettingNotFoundException e) { + Slog.e(TAG,"AP settings not found, returning"); + return null; + } + } + + private void persistApConfiguration(WifiConfiguration wifiConfig) { + final ContentResolver cr = mContext.getContentResolver(); + boolean isWpa; + if (wifiConfig == null) + return; + Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID); + isWpa = wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK); + Settings.Secure.putInt(cr, + Settings.Secure.WIFI_AP_SECURITY, + isWpa ? KeyMgmt.WPA_PSK : KeyMgmt.NONE); + if (isWpa) + Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey); + } + /** * Enables/disables Wi-Fi AP synchronously. The driver is loaded * and soft access point configured as a single operation. * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off. - * @param persist {@code true} if the setting should be persisted. * @param uid The UID of the process making the request. - * @param config The WifiConfiguration for AP + * @param wifiConfig The WifiConfiguration for AP * @return {@code true} if the operation succeeds (or if the existing state * is the same as the requested state) */ - /** - * TODO: persist needs to go away in WifiService - * This will affect all persist related functions - * for Access Point - */ private boolean setWifiApEnabledBlocking(boolean enable, - boolean persist, int uid, WifiConfiguration wifiConfig) { + int uid, WifiConfiguration wifiConfig) { final int eventualWifiApState = enable ? WIFI_AP_STATE_ENABLED : WIFI_AP_STATE_DISABLED; if (mWifiApState == eventualWifiApState) { - return true; + /* Configuration changed on a running access point */ + if(enable && (wifiConfig != null)) { + try { + persistApConfiguration(wifiConfig); + nwService.stopAccessPoint(); + nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName()); + return true; + } catch(Exception e) { + Slog.e(TAG, "Exception in nwService during AP restart"); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD); + return false; + } + } else { + return true; + } } - setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING : WIFI_AP_STATE_DISABLING, uid); - - if (enable && (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED)) { - setWifiEnabledBlocking(false, true, Process.myUid()); - } + setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING : + WIFI_AP_STATE_DISABLING, uid, DriverAction.NO_DRIVER_UNLOAD); if (enable) { + + /** + * Disable client mode for starting AP + */ + if (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) { + setWifiEnabledBlocking(false, true, Process.myUid()); + } + + /* Use default config if there is no existing config */ + if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) { + wifiConfig = new WifiConfiguration(); + wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default); + wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE); + } + persistApConfiguration(wifiConfig); + if (!mWifiStateTracker.loadDriver()) { Slog.e(TAG, "Failed to load Wi-Fi driver for AP mode"); - setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD); return false; } try { - nwService.startAccessPoint(); + nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName()); } catch(Exception e) { Slog.e(TAG, "Exception in startAccessPoint()"); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD); + return false; } } else { @@ -669,20 +705,18 @@ public class WifiService extends IWifiManager.Stub { nwService.stopAccessPoint(); } catch(Exception e) { Slog.e(TAG, "Exception in stopAccessPoint()"); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD); + return false; } if (!mWifiStateTracker.unloadDriver()) { Slog.e(TAG, "Failed to unload Wi-Fi driver for AP mode"); - setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD); return false; } } - // Success! - if (persist) { - persistWifiApEnabled(enable); - } - setWifiApEnabledState(eventualWifiApState, uid); + setWifiApEnabledState(eventualWifiApState, uid, DriverAction.NO_DRIVER_UNLOAD); return true; } @@ -699,9 +733,16 @@ public class WifiService extends IWifiManager.Stub { return mWifiApState; } - private void setWifiApEnabledState(int wifiAPState, int uid) { + private void setWifiApEnabledState(int wifiAPState, int uid, DriverAction flag) { final int previousWifiApState = mWifiApState; + /** + * Unload the driver if going to a failed state + */ + if ((mWifiApState == WIFI_AP_STATE_FAILED) && (flag == DriverAction.DRIVER_UNLOAD)) { + mWifiStateTracker.unloadDriver(); + } + long ident = Binder.clearCallingIdentity(); try { if (wifiAPState == WIFI_AP_STATE_ENABLED) { @@ -1694,7 +1735,7 @@ public class WifiService extends IWifiManager.Stub { private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) { Message.obtain(mWifiHandler, (enable ? MESSAGE_START_ACCESS_POINT : MESSAGE_STOP_ACCESS_POINT), - 0, uid, wifiConfig).sendToTarget(); + uid, 0, wifiConfig).sendToTarget(); } private void updateWifiState() { @@ -1841,15 +1882,13 @@ public class WifiService extends IWifiManager.Stub { case MESSAGE_START_ACCESS_POINT: setWifiApEnabledBlocking(true, - msg.arg1 == 1, - msg.arg2, + msg.arg1, (WifiConfiguration) msg.obj); break; case MESSAGE_STOP_ACCESS_POINT: setWifiApEnabledBlocking(false, - msg.arg1 == 1, - msg.arg2, + msg.arg1, (WifiConfiguration) msg.obj); sWakeLock.release(); break; diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index d5f2c1d..e43b12e 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -1502,7 +1502,7 @@ public class StatusBarService extends IStatusBar.Stub Drawable bg; /// ---------- Tracking View -------------- - pixelFormat = PixelFormat.TRANSLUCENT; + pixelFormat = PixelFormat.RGBX_8888; bg = mTrackingView.getBackground(); if (bg != null) { pixelFormat = bg.getOpacity(); diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java index c1c8c22..b3ee257 100644 --- a/services/java/com/android/server/status/UsbStorageActivity.java +++ b/services/java/com/android/server/status/UsbStorageActivity.java @@ -28,6 +28,7 @@ import android.content.IntentFilter; import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; import android.os.Environment; +import android.os.Handler; import android.os.IBinder; import android.os.storage.IMountService; import android.os.storage.StorageManager; @@ -36,8 +37,10 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.widget.ImageView; import android.widget.Button; +import android.widget.ProgressBar; import android.widget.TextView; import android.view.View; +import android.view.Window; import android.util.Log; /** @@ -48,8 +51,10 @@ import android.util.Log; public class UsbStorageActivity extends Activity implements View.OnClickListener, OnCancelListener { private static final String TAG = "UsbStorageActivity"; + private Button mMountButton; private Button mUnmountButton; + private ProgressBar mProgressBar; private TextView mBanner; private TextView mMessage; private ImageView mIcon; @@ -71,11 +76,8 @@ public class UsbStorageActivity extends Activity private StorageEventListener mStorageListener = new StorageEventListener() { @Override public void onStorageStateChanged(String path, String oldState, String newState) { - if (newState.equals(Environment.MEDIA_SHARED)) { - switchDisplay(true); - } else { - switchDisplay(false); - } + final boolean on = newState.equals(Environment.MEDIA_SHARED); + switchDisplay(on); } }; @@ -90,6 +92,9 @@ public class UsbStorageActivity extends Activity } } + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + setProgressBarIndeterminateVisibility(true); + setTitle(getString(com.android.internal.R.string.usb_storage_activity_title)); setContentView(com.android.internal.R.layout.usb_storage_activity); @@ -102,16 +107,19 @@ public class UsbStorageActivity extends Activity mMountButton.setOnClickListener(this); mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button); mUnmountButton.setOnClickListener(this); + mProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress); } private void switchDisplay(boolean usbStorageInUse) { if (usbStorageInUse) { + mProgressBar.setVisibility(View.GONE); mUnmountButton.setVisibility(View.VISIBLE); mMountButton.setVisibility(View.GONE); mIcon.setImageResource(com.android.internal.R.drawable.usb_android_connected); mBanner.setText(com.android.internal.R.string.usb_storage_stop_title); mMessage.setText(com.android.internal.R.string.usb_storage_stop_message); } else { + mProgressBar.setVisibility(View.GONE); mUnmountButton.setVisibility(View.GONE); mMountButton.setVisibility(View.VISIBLE); mIcon.setImageResource(com.android.internal.R.drawable.usb_android); @@ -189,6 +197,25 @@ public class UsbStorageActivity extends Activity showDialog(id); } + private void switchUsbMassStorageAsync(boolean on) { + mUnmountButton.setVisibility(View.GONE); + mMountButton.setVisibility(View.GONE); + + mProgressBar.setVisibility(View.VISIBLE); + // will be hidden once USB mass storage kicks in (or fails) + + final boolean _on = on; + new Thread() { + public void run() { + if (_on) { + mStorageManager.enableUsbMassStorage(); + } else { + mStorageManager.disableUsbMassStorage(); + } + } + }.start(); + } + private void checkStorageUsers() { IMountService ims = getMountService(); if (ims == null) { @@ -208,18 +235,17 @@ public class UsbStorageActivity extends Activity showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS); } else { if (localLOGV) Log.i(TAG, "Enabling UMS"); - mStorageManager.enableUsbMassStorage(); + switchUsbMassStorageAsync(true); } } public void onClick(View v) { - Log.i(TAG, "Clicked button"); if (v == mMountButton) { // Check for list of storage users and display dialog if needed. checkStorageUsers(); } else if (v == mUnmountButton) { if (localLOGV) Log.i(TAG, "Disabling UMS"); - mStorageManager.disableUsbMassStorage(); + switchUsbMassStorageAsync(false); } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java index 8c8b00c..a06a13b 100755 --- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java @@ -72,8 +72,8 @@ import android.provider.Settings.SettingNotFoundException; public class PackageManagerTests extends AndroidTestCase { private static final boolean localLOGV = true; public static final String TAG="PackageManagerTests"; - public final long MAX_WAIT_TIME=120*1000; - public final long WAIT_TIME_INCR=20*1000; + public final long MAX_WAIT_TIME = 25*1000; + public final long WAIT_TIME_INCR = 5*1000; private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec"; private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO; private static final int APP_INSTALL_DEVICE = PackageHelper.APP_INSTALL_INTERNAL; @@ -378,39 +378,50 @@ public class PackageManagerTests extends AndroidTestCase { private InstallParams installFromRawResource(String outFileName, int rawResId, int flags, boolean cleanUp, boolean fail, int result, int expInstallLocation) { + PackageManager pm = mContext.getPackageManager(); File filesDir = mContext.getFilesDir(); File outFile = new File(filesDir, outFileName); Uri packageURI = getInstallablePackage(rawResId, outFile); PackageParser.Package pkg = parsePackage(packageURI); assertNotNull(pkg); - InstallParams ip = null; - // Make sure the package doesn't exist - getPm().deletePackage(pkg.packageName, null, 0); - // Clean up the containers as well - clearSecureContainersForPkg(pkg.packageName); - try { + if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) { + // Make sure the package doesn't exist try { - if (fail) { - assertTrue(invokeInstallPackageFail(packageURI, flags, - pkg.packageName, result)); - assertNotInstalled(pkg.packageName); - } else { - InstallReceiver receiver = new InstallReceiver(pkg.packageName); - assertTrue(invokeInstallPackage(packageURI, flags, - pkg.packageName, receiver)); - // Verify installed information - assertInstall(pkg, flags, expInstallLocation); - ip = new InstallParams(pkg, outFileName, packageURI); - } + ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName, + PackageManager.GET_UNINSTALLED_PACKAGES); + GenericReceiver receiver = new DeleteReceiver(pkg.packageName); + invokeDeletePackage(packageURI, 0, + pkg.packageName, receiver); + } catch (NameNotFoundException e1) { } catch (Exception e) { - failStr("Failed with exception : " + e); + failStr(e); + } + // Clean up the containers as well + clearSecureContainersForPkg(pkg.packageName); + } + InstallParams ip = null; + try { + if (fail) { + assertTrue(invokeInstallPackageFail(packageURI, flags, + pkg.packageName, result)); + assertNotInstalled(pkg.packageName); + } else { + InstallReceiver receiver = new InstallReceiver(pkg.packageName); + assertTrue(invokeInstallPackage(packageURI, flags, + pkg.packageName, receiver)); + // Verify installed information + assertInstall(pkg, flags, expInstallLocation); + ip = new InstallParams(pkg, outFileName, packageURI); } return ip; + } catch (Exception e) { + failStr("Failed with exception : " + e); } finally { if (cleanUp) { cleanUpInstall(ip); } } + return ip; } @MediumTest @@ -820,7 +831,7 @@ public class PackageManagerTests extends AndroidTestCase { try { // Wait on observer synchronized(observer) { - getMs().unmountVolume(path, false); + getMs().unmountVolume(path, true); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { observer.wait(WAIT_TIME_INCR); @@ -949,14 +960,21 @@ public class PackageManagerTests extends AndroidTestCase { PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); } - private void replaceManifestLocation(int iFlags, int rFlags) { + /* + * Install a package on internal flash via PackageManager install flag. Replace + * the package via flag to install on sdcard. Make sure the new flag overrides + * the old install location. + */ + public void testReplaceFlagInternalSdcard() { + int iFlags = 0; + int rFlags = PackageManager.INSTALL_EXTERNAL; InstallParams ip = sampleInstallFromRawResource(iFlags, false); GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; try { assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, ip.pkg.packageName, receiver), true); - assertInstall(ip.pkg, replaceFlags, ip.pkg.installLocation); + assertInstall(ip.pkg, rFlags, ip.pkg.installLocation); } catch (Exception e) { failStr("Failed with exception : " + e); } finally { @@ -964,12 +982,26 @@ public class PackageManagerTests extends AndroidTestCase { } } - public void testReplaceFlagInternalSdcard() { - replaceManifestLocation(0, PackageManager.INSTALL_EXTERNAL); - } - + /* + * Install a package on sdcard via PackageManager install flag. Replace + * the package with no flags or manifest option and make sure the old + * install location is retained. + */ public void testReplaceFlagSdcardInternal() { - replaceManifestLocation(PackageManager.INSTALL_EXTERNAL, 0); + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = 0; + InstallParams ip = sampleInstallFromRawResource(iFlags, false); + GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); + int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; + try { + assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, + ip.pkg.packageName, receiver), true); + assertInstall(ip.pkg, iFlags, ip.pkg.installLocation); + } catch (Exception e) { + failStr("Failed with exception : " + e); + } finally { + cleanUpInstall(ip); + } } public void testManifestInstallLocationReplaceInternalSdcard() { @@ -984,7 +1016,7 @@ public class PackageManagerTests extends AndroidTestCase { int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; try { InstallParams rp = installFromRawResource("install.apk", rApk, - rFlags, false, + replaceFlags, false, false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); assertInstall(rp.pkg, replaceFlags, rp.pkg.installLocation); } catch (Exception e) { @@ -1002,11 +1034,10 @@ public class PackageManagerTests extends AndroidTestCase { InstallParams ip = installFromRawResource("install.apk", iApk, iFlags, false, false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; try { InstallParams rp = installFromRawResource("install.apk", rApk, - rFlags, false, + replaceFlags, false, false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); assertInstall(rp.pkg, replaceFlags, ip.pkg.installLocation); } catch (Exception e) { @@ -1211,6 +1242,56 @@ public class PackageManagerTests extends AndroidTestCase { moveFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.MOVE_INTERNAL, PackageManager.MOVE_SUCCEEDED); } + + /* + * Test that an install error code is returned when media is unmounted + * and package installed on sdcard via package manager flag. + */ + public void testInstallSdcardUnmount() { + boolean origState = getMediaState(); + try { + // Unmount sdcard + assertTrue(unmountMedia()); + // Try to install and make sure an error code is returned. + assertNull(installFromRawResource("install.apk", R.raw.install, + PackageManager.INSTALL_EXTERNAL, false, + true, PackageManager.INSTALL_FAILED_CONTAINER_ERROR, + PackageInfo.INSTALL_LOCATION_AUTO)); + } finally { + // Restore original media state + if (origState) { + mountMedia(); + } else { + unmountMedia(); + } + } + } + + /* + * Unmount sdcard. Try installing an app with manifest option to install + * on sdcard. Make sure it gets installed on internal flash. + */ + public void testInstallManifestSdcardUnmount() { + boolean origState = getMediaState(); + try { + // Unmount sdcard + assertTrue(unmountMedia()); + // Try to install and make sure an error code is returned. + assertNotNull(installFromRawResource("install.apk", R.raw.install_loc_sdcard, + 0, false, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY)); + } finally { + // Restore original media state + if (origState) { + mountMedia(); + } else { + unmountMedia(); + } + } + } + + /*---------- Recommended install location tests ----*/ /* * TODO's * check version numbers for upgrades diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index d833e33..5fd44b1 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -81,5 +81,7 @@ interface IWifiManager boolean setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable); int getWifiApEnabledState(); + + WifiConfiguration getWifiApConfiguration(); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9ef8ba1..970d5fc 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -810,6 +810,20 @@ public class WifiManager { } /** + * Gets the Wi-Fi AP Configuration. + * @return AP details in WifiConfiguration + * + * @hide Dont open yet + */ + public WifiConfiguration getWifiApConfiguration() { + try { + return mService.getWifiApConfiguration(); + } catch (RemoteException e) { + return null; + } + } + + /** * Allows an application to keep the Wi-Fi radio awake. * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple |