blob: 28919bf13c80c6b64f5164e6841d316475a23690 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
# This script relies on the Unicode install of NSIS. If you use vanilla NSIS,
# this script won't compile. http://www.scratchpaper.com/
# IMPORTANT: to run this script, the defines DIR_SRC and DIR_SDK (if BUNDLE_SDK
# is set) must exist and point to the absolute path where those components can
# be found.
#
# This should look like the following:
# $DIR_SRC\android-studio\
# $DIR_SDK\android-sdk.7z
#
# DIR_SRC and DIR_SDK can be set to the same location.
# If uncommented, DRY_RUN visits every page but doesn't actually install
# anything.
#!define DRY_RUN
# If uncommented, this script will build an intermediate uninstall_builder.exe
# which generates an uninstaller when run. This extra step allows us to sign the
# uninstaller. See also: http://nsis.sourceforge.net/Signing_an_Uninstaller
# NOTE: Be sure to run uninstall_builder.exe from the same working directory
# that contains this script so the final uninstaller is put in the right
# location.
#!define UNINSTALL_BUILDER
# If uncommented, bundle the SDK with the installer. This adds ~500MB to the
# installer's size.
#!define BUNDLE_SDK
# If uncommented, bundle the Microsoft redistributables with the installer.
# This is a dependency we hope to remove, eventually, after we rebuild all tool
# exes so they statically link MSVC++ libraries instead of loading them
# dynamically.
#!define DIR_MSREDIST ..\..\..\microsoft
# If uncommented, bundle Intel HAXM with the installer.
#!define DIR_HAXM ..\..\..\intel
# TODO(davidherman): We need to temporarily hide our sidebar, header, and icon
# assets until we're ready to unveil our new logo. After that point, we can
# safely remove this define and all references to it.
#!define HIDE_ASSETS
Unicode true
!define APP_NAME "Android Studio"
Name "${APP_NAME}"
!ifndef DRY_RUN && UNINSTALL_BUILDER
!ifndef DIR_SRC
!warning "DIR_SRC should be defined! This script won't work without it."
CompileErrorOnPurpose
!endif
!ifdef BUNDLE_SDK
!ifndef DIR_SDK
!warning "DIR_SDK should be defined! This script won't work without it."
CompileErrorOnPurpose
!endif
!endif
!endif
!ifndef UNINSTALL_BUILDER
# Via the UAC plugin, we start our installer as a user process, collect
# information about the current user, and then elevate to an admin installer.
# See http://nsis.sourceforge.net/UAC_plug-in for details
RequestExecutionLevel user
!else
RequestExecutionLevel admin # The uninstaller always runs in admin mode
!endif
# General Symbol Definitions
!define REGKEY "SOFTWARE\${APP_NAME}"
!define EXE_NAME_32 "studio.exe"
!define EXE_NAME_64 "studio64.exe"
!define FIND_JAVA_EXE_32 "find_java32.exe"
!define FIND_JAVA_EXE_64 "find_java64.exe"
!define USER_ADMIN_HANDOFF_FILE "inst_user_settings.tmp"
!define DEFAULT_STUDIO_PATH "$PROGRAMFILES\Android\Android Studio"
!define DEFAULT_SDK_PATH "$PROFILE\AppData\Local\Android\sdk"
!define ANDROID_USER_SETTINGS "$PROFILE\.android"
!define VERSION_MAJOR 1
!define VERSION_MINOR 0
!define VERSION ${VERSION_MAJOR}.${VERSION_MINOR}
!define VENDOR Android
!define COMPANY "Google Inc."
!define URL http://developer.android.com
# MUI Symbol Definitions
!ifndef HIDE_ASSETS
!define MUI_ICON "assets\studio-inst.ico"
!else
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\orange-install.ico"
!endif
!ifndef DRY_RUN
# Abort normally, but dry runs are for testing, and we often want to test,
# quit, and iterate in that case, so don't slow us down then.
!define MUI_ABORTWARNING
!endif
!define MUI_FINISHPAGE_NOAUTOCLOSE
!ifndef HIDE_ASSETS
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "assets\header.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP "assets\sidebar.bmp"
!endif
!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${REGKEY}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${APP_NAME}"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_TEXT "Start ${APP_NAME}"
!define MUI_FINISHPAGE_RUN_FUNCTION s_StartApp
!ifndef HIDE_ASSETS
!define MUI_UNICON ${MUI_ICON} # Our studio install icon is generic, so just re-use it for uninstall
!else
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\orange-uninstall.ico"
!endif
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
# Included files
!include UAC.nsh
!include Sections.nsh
!include MUI2.nsh
!include x64.nsh
!include LogicLib.nsh
!include WinVer.nsh
!include nsDialogs.nsh
!include StrFunc.nsh
!include FileFunc.nsh
!include StrContains.nsh
!include TimeStamp.nsh
# StrFunc.nsh requires priming the commands which actually get used later
${StrRep}
# Helper defines for Sections.nsh
!define SelectSection '!insertmacro SelectSection'
!define UnselectSection '!insertmacro UnselectSection'
# Installer attributes
!ifndef UNINSTALL_BUILDER
OutFile setup.exe
!else
OutFile "uninstall_builder.exe"
SetCompress off
!endif
CRCCheck on
XPStyle on
BrandingText " " # Branding footer disabled
ShowInstDetails hide
ShowUninstDetails hide
# Right-click installer .exe -> Properties -> Details
VIProductVersion ${VERSION}.0.0
VIAddVersionKey ProductName "${APP_NAME}"
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}"
VIAddVersionKey FileVersion "${VERSION}"
VIAddVersionKey FileDescription ""
VIAddVersionKey LegalCopyright ""
ShowUninstDetails hide
# Page Constants
!define JDK_EXE_32 "jdk-7u67-windows-i586.exe" # TODO: Stop hardcoding these after Studio 1.0
!define JDK_EXE_64 "jdk-7u67-windows-x64.exe"
!define JDK_LINK "http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html"
# Variables
Var s_DefaultSdkPath
Var s_UserSettingsPath
Var s_SystemMemoryMB
Var s_SystemMemoryGB
Var s_InstallHaxmBat
Var s_FindJavaExe
Var s_JdkPath
Var s_StudioPath
Var s_SdkPath
Var s_InstallSdk # 0 (skip install) or non-zero (include install)
Var s_InstallHaxm # 0 (skip install) or non-zero (include install)
Var s_SdkReferencePath # Path where we installed the latest SDK to. Will be
# different from s_SdkPath if user asks to use an
# existing SDK.
Var s_SkipAndroidLicense # If 1, skip the license (we saw it already)
Var s_SkipIntelLicense
Var s_StartMenuGroup
# Page definitions
# Generated by CoolSoft NSIS Dialog Designer
!include PageDefns\UninstallPreviousPage.nsdinc
!include PageDefns\FindJavaPage.nsdinc
!include PageDefns\AndroidSdkPage.nsdinc
!include PageDefns\InstallDirsPage.nsdinc
!include PageDefns\HaxmPage.nsdinc
# ---------- Pages -------------------------------------------
Page custom fnc_UninstallPreviousPage_ShowIfNecessary func_UninstallPreviousPage_Leave
# Installer pages
!insertmacro MUI_PAGE_WELCOME
Page custom fnc_FindJavaPage_ShowIfNecessary fnc_FindJavaPage_Leave
!define MUI_PAGE_CUSTOMFUNCTION_PRE s_ComponentsPagePre
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE s_ComponentsPageLeave
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_PRE s_AndroidLicensePagePre
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE s_AndroidLicensePageLeave
!insertmacro MUI_PAGE_LICENSE licenses/android.txt
!define MUI_PAGE_CUSTOMFUNCTION_PRE s_IntelLicensePagePre
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE s_IntelLicensePageLeave
!insertmacro MUI_PAGE_LICENSE licenses/intel.txt
Page custom fnc_AndroidSdkPage_ShowIfNecessary fnc_AndroidSdkPage_Leave
Page custom fnc_InstallDirsPage_Show fnc_InstallDirsPage_Leave
Page custom fnc_HaxmPage_ShowIfNecessary fnc_HaxmPage_Leave
!insertmacro MUI_PAGE_STARTMENU Application $s_StartMenuGroup
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
# Uninstaller pages
!insertmacro MUI_UNPAGE_COMPONENTS
!define MUI_UNCONFIRMPAGE_TEXT_TOP "Click uninstall to begin the process."
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.s_ConfirmPageLeave
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
# Installer languages
!insertmacro MUI_LANGUAGE English
# ---------- Sections ----------------------------------------
# Hide a section and make sure it's unselected
!macro EXCLUDE_SECTION SECTION_ID
# In NSIS, the way you hide a section is by clearing its text
${UnselectSection} ${SECTION_ID}
SectionSetText ${SECTION_ID} ""
!macroend
# Simple macro to call before using the HAXM installer. After calling this,
# $s_InstallHaxmBat will be set.
!macro PREPARE_HAXM_INSTALLER
!ifdef DIR_HAXM
File ${DIR_HAXM}\intelhaxm-android.exe
File ${DIR_HAXM}\silent_install.bat
StrCpy $s_InstallHaxmBat "$OUTDIR\silent_install.bat"
!endif
!macroend
# Run the HAXM installer with the following argument string.
!macro RUN_HAXM_INSTALLER ARG_STR ERROR_CODE_VAR STDOUT_VAR
!ifdef DIR_HAXM
# Save existing variables
Push $0
Push $OUTDIR
${GetParent} "$s_InstallHaxmBat" $0
SetOutPath $0 # Sets $OUTDIR and the cwd
${If} ${RunningX64}
${DisableX64FSRedirection} # Ensure HAXM bat runs in 64-bit mode
${EndIf}
nsExec::ExecToStack '"$s_InstallHaxmBat" ${ARG_STR}'
# We restore $0 first, because if one of the macro args happens to also be
# $0, restoring it second would overwrite the arg.
# Stack (from bottom to top): $0, $OUTDIR, $STDOUT, $ERROR
Exch 3 # $ERROR, $OUTDIR, $STDOUT, $0
Pop $0
Pop ${STDOUT_VAR}
Pop $OUTDIR
Pop ${ERROR_CODE_VAR}
SetOutPath $OUTDIR
!else
StrCpy ${ERROR_CODE_VAR} 1
StrCpy ${STDOUT_VAR} "Installer not bundled with HAXM"
!endif # DIR_HAXM
!macroend
# Call this macro to see if HAXM is installable on the system. If so, OUT_VAR
# will be set to 1, 0 otherwise. This macro should only be called after
# PREPARE_HAXM_INSTALLER is called.
!macro CAN_INSTALL_HAXM OUT_VAR
!insertmacro RUN_HAXM_INSTALLER "-c" $R0 $R1
# Error code is 0 if you can install haxm, non-zero otherwise
IntOp ${OUT_VAR} $R0 ! # $OUT_VAR = !$R0
!macroend
# Silently install HAXM. This macro should only be called after
# PREPARE_HAXM_INSTALLER is called.
!macro INSTALL_HAXM MEMORY_MB OUT_VAR MESSAGE
!insertmacro RUN_HAXM_INSTALLER "-m ${MEMORY_MB}" ${OUT_VAR} ${MESSAGE}
# RUN_HAXM_INSTALLER sets OUT_VAR to 0 on success, non-zero otherwise
# Change OUT_VAR to 0 on failure, 1 otherwise
IntOp ${OUT_VAR} ${OUT_VAR} ! # OUT_VAR = !OUT_VAR
!macroend
# Silently uninstall HAXM. This macro should only be called after
# PREPARE_HAXM_INSTALLER is called.
!macro UNINSTALL_HAXM
!insertmacro RUN_HAXM_INSTALLER "-u" $R0 $R1
# We currently don't care about the return values for this step - it either
# worked or it didn't, and we succeed or fail silently.
!macroend
# Call this macro to see if HAXM is already installed on the system. If so,
# OUT_VAR will be set to 1, 0 otherwise. This macro should only be called after
# PREPARE_HAXM_INSTALLER is called.
!macro IS_HAXM_INSTALLED OUT_VAR
!insertmacro RUN_HAXM_INSTALLER "-v" $R0 $R1
# Error-code is 0 on installed, non-zero otherwise
IntOp ${OUT_VAR} $R0 ! # $OUT_VAR = !$R0
!macroend
# Requires the user to stop Studio, if it's running, or else we should abort.
# It's expected that this macro should be used in onInit functions.
!macro STOP_STUDIO_PROCESS
StrCpy $R2 1 # This var means continue looping. Set to 0 to escape.
${DoWhile} $R2 == 1
FindProcDLL::FindProc ${EXE_NAME_32} # Sets $R0 to 1 if found
StrCpy $R1 $R0
FindProcDLL::FindProc ${EXE_NAME_64}
${If} $R0 != 1
${AndIf} $R1 != 1
StrCpy $R2 0
${Else}
MessageBox MB_OKCANCEL "Android Studio is currently running. \
Please exit the application and press OK to continue with the installation."\
IDOK tryagain IDCANCEL 0
MessageBox MB_OK "Uninstalling Android Studio has been aborted. Please try again later."
Abort
tryagain:
${EndIf}
${Loop}
!macroend
# Installer sections
Section "Android Studio" SectionStudio
SectionIn RO # Can't deselect this section
!ifndef DRY_RUN && UNINSTALL_BUILDER
SetOutPath $s_StudioPath
SetOverwrite on
File /r "${DIR_SRC}\android-studio\*"
!endif # DRY_RUN && UNINSTALL_BUILDER
SectionEnd
!ifdef BUNDLE_SDK
Section "Android SDK" SectionSdk
# Final size on disk: 2.2+GB. Add size until components page shows 2.3GB
AddSize 1930000
!ifndef DRY_RUN && UNINSTALL_BUILDER
SetOutPath $TEMP
SetOverwrite on
SetCompress off
File "${DIR_SDK}\android-sdk.7z"
SetCompress auto
${If} $s_InstallSdk != 0
StrCpy $s_SdkReferencePath "$s_SdkPath"
StrCpy $R0 "Extracting Android SDK... %s"
${Else}
StrCpy $s_SdkReferencePath "$TEMP\Android Sdk"
# Should be rare, but perhaps a reference SDK was left over from a previous install
RMDir /r $s_SdkReferencePath
StrCpy $R0 "Preparing reference SDK for Android Studio first launch... %s"
${EndIf}
SetOutPath "$s_SdkReferencePath"
Nsis7z::ExtractWithDetails "$TEMP\android-sdk.7z" "$R0"
Delete "$TEMP\android-sdk.7z"
!endif # DRY_RUN && UNINSTALL_BUILDER
SectionEnd
!endif # BUNDLE_SDK
Section "Android Virtual Device" SectionAvd
# Dummy section for AVD creation. We actually don't do anything here but
# hand off the work to the Studio first run wizard. See SectionFirstRun.
AddSize 1048576 # == 1GB. AVD creation creates a 1GB virtual device.
SectionEnd
Section "Performance (Intel® HAXM)" SectionHaxm
!ifndef DRY_RUN && UNINSTALL_BUILDER
!insertmacro INSTALL_HAXM "$var_HaxmPage_SelectedMB" $R0 $R1
${If} $R0 == 0
MessageBox MB_OK $R1 /SD IDOK
${Endif}
!endif # DRY_RUN && UNINSTALL_BUILDER
SectionEnd
# MS VC Redistributable
Section -Redist SectionRedist
!ifdef DIR_MSREDIST
!ifndef DRY_RUN && UNINSTALL_BUILDER
SetOutPath $TEMP
# Always add the VS.Net 2008 and 2010 redistributable CRT installers, relative to this script
# Note: /q:a is "almost silent with progress bar", /q is totally silent but might
# still display an EULA & install page on some systems.
File ${DIR_MSREDIST}\vcredist_x86_2008.exe
ExecWait '"$TEMP\vcredist_x86_2008.exe" /q:a'
Delete /REBOOTOK "$TEMP\vcredist_x86_2008.exe"
${If} ${RunningX64}
File ${DIR_MSREDIST}\vcredist_x64_2008.exe
ExecWait '"$TEMP\vcredist_x64_2008.exe" /q:a'
Delete /REBOOTOK "$TEMP\vcredist_x64_2008.exe"
${EndIf}
File ${DIR_MSREDIST}\vcredist_x86_2010.exe
ExecWait '"$TEMP\vcredist_x86_2010.exe" /passive /norestart /showfinalerror'
Delete /REBOOTOK "$TEMP\vcredist_x86_2010.exe"
${If} ${RunningX64}
File ${DIR_MSREDIST}\vcredist_x64_2010.exe
ExecWait '"$TEMP\vcredist_x64_2010.exe" /passive /norestart /showfinalerror'
Delete /REBOOTOK "$TEMP\vcredist_x64_2010.exe"
${EndIf}
!endif # DRY_RUN && UNINSTALL_BUILDER
!endif # DIR_MSREDIST
SectionEnd
Section -Post SectionSystem
!ifndef DRY_RUN && UNINSTALL_BUILDER
WriteRegStr HKLM "${REGKEY}" Path $s_StudioPath
SetOutPath $s_StudioPath
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
SetOutPath $SMPROGRAMS\$s_StartMenuGroup
${If} ${RunningX64}
CreateShortcut "$SMPROGRAMS\$s_StartMenuGroup\${APP_NAME}.lnk" "$s_StudioPath\bin\${EXE_NAME_64}"
${Else}
CreateShortcut "$SMPROGRAMS\$s_StartMenuGroup\${APP_NAME}.lnk" "$s_StudioPath\bin\${EXE_NAME_32}"
${EndIf}
!insertmacro MUI_STARTMENU_WRITE_END
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" DisplayName "${APP_NAME}"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" DisplayVersion "${VERSION}"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" Publisher "${COMPANY}"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" URLInfoAbout "${URL}"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" DisplayIcon "$s_StudioPath\bin\${EXE_NAME_32}"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" UninstallString $s_StudioPath\uninstall.exe
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" NoModify 1
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" NoRepair 1
WriteRegStr HKLM "${REGKEY}" JdkPath "$s_JdkPath"
WriteRegStr HKLM "${REGKEY}" SdkPath "$s_SdkPath"
WriteRegStr HKLM "${REGKEY}" UserSettingsPath "$s_UserSettingsPath"
WriteRegStr HKLM "${REGKEY}" InstallSdk "$s_InstallSdk"
WriteRegStr HKLM "${REGKEY}" InstallHaxm "$s_InstallHaxm"
!endif # DRY_RUN && UNINSTALL_BUILDER
SectionEnd
Section -FirstRun SectionFirstRun
!ifndef DRY_RUN && UNINSTALL_BUILDER
StrCpy $R9 "false" # Set $R9 to [true|false] if Studio should create an AVD
SectionGetFlags ${SectionAvd} $R8
IntOp $R8 $R8 & ${SF_SELECTED}
${If} $R8 != 0
StrCpy $R9 "true"
${EndIf}
${TimeStamp} $R7
# Write out the installer->studio handoff file into the user's .android directory
SetOutPath $PROFILE
SetOverwrite on
CreateDirectory "$s_UserSettingsPath\studio"
CreateDirectory "$s_UserSettingsPath\studio\installer"
FileOpen $R0 "$s_UserSettingsPath\studio\installer\firstrun.data" w
# Even though NSIS is writing out UTF16LE, it doesn't provide an option to write out a BOM,
# which means our file would open incorrectly in a lot of editors. So, we do it ourselves.
# The BOM for UTF16LE is FFFE. http://en.wikipedia.org/wiki/Byte_order_mark
FileWriteByte $R0 255
FileWriteByte $R0 254
FileWriteUTF16LE $R0 "# This file's encoding is UTF-16LE. If modified, preserve the encoding!$\r$\n"
FileWriteUTF16LE $R0 "$\r$\n"
FileWriteUTF16LE $R0 "# Location of the user's JDK$\r$\n"
FileWriteUTF16LE $R0 "jdk.dir=$s_JdkPath$\r$\n"
FileWriteUTF16LE $R0 "$\r$\n"
FileWriteUTF16LE $R0 "# Location of the user's Android SDK$\r$\n"
FileWriteUTF16LE $R0 "androidsdk.dir=$s_SdkPath$\r$\n"
FileWriteUTF16LE $R0 "$\r$\n"
FileWriteUTF16LE $R0 "# Location of a reference Android SDK that just has the latest files$\r$\n"
FileWriteUTF16LE $R0 "androidsdk.repo=$s_SdkReferencePath$\r$\n"
FileWriteUTF16LE $R0 "$\r$\n"
FileWriteUTF16LE $R0 "# If true, create a default AVD with optimized settings$\r$\n"
FileWriteUTF16LE $R0 "create.avd=$R9$\r$\n"
FileWriteUTF16LE $R0 "$\r$\n"
FileWriteUTF16LE $R0 "# The UTC timestamp when this installer ran$\r$\n"
FileWriteUTF16LE $R0 "install.timestamp=$R7$\r$\n"
FileClose $R0
!endif # DRY_RUN && UNINSTALL_BUILDER
SectionEnd
# Uninstaller sections
Section "un.Android Studio" UNSectionStudio
SectionIn RO # Can't deselect this section
!ifndef DRY_RUN
# Don't set REBOOTOK here, or else we may end up installing a new version
# of Android Studio in this path which gets removed on reboot!
RmDir /r $s_StudioPath
!endif # DRY_RUN
SectionEnd
Section "un.Android SDK" UNSectionSdk
!ifndef DRY_RUN
RmDir /r /REBOOTOK $s_SdkPath
!endif # DRY_RUN
SectionEnd
Section "un.Performance (Intel® HAXM)" UNSectionHaxm
!ifndef DRY_RUN
!insertmacro UNINSTALL_HAXM
!endif
SectionEnd
Section -un.FirstRun UNSectionFirstRun
!ifndef DRY_RUN
RmDir /r /REBOOTOK "$s_UserSettingsPath\studio\installer"
RmDir "$s_UserSettingsPath\studio" # Remove if empty
!endif
SectionEnd
Section "un.Android User Settings" UNSectionUserSettings
!ifndef DRY_RUN
RmDir /r /REBOOTOK "${ANDROID_USER_SETTINGS}\"
!endif
SectionEnd
Section -un.Post UNSectionSystem
!ifndef DRY_RUN
DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
DeleteRegValue HKLM "${REGKEY}" StartMenuGroup
DeleteRegValue HKLM "${REGKEY}" Path
DeleteRegValue HKLM "${REGKEY}" JdkPath
DeleteRegValue HKLM "${REGKEY}" SdkPath
DeleteRegValue HKLM "${REGKEY}" InstallSdk
DeleteRegValue HKLM "${REGKEY}" InstallHaxm
DeleteRegValue HKLM "${REGKEY}" UserSettingsPath
DeleteRegKey /IfEmpty HKLM "${REGKEY}"
Delete /REBOOTOK "$SMPROGRAMS\$s_StartMenuGroup\${APP_NAME}.lnk"
RmDir /REBOOTOK "$SMPROGRAMS\$s_StartMenuGroup"
!endif # DRY_RUN
SectionEnd
# If you add a new uninstall section, and it shouldn't be run if all we're doing
# is overwriting an existing version of Studio, then update the logic in
# un.onInit to exclude the section from running in silent mode.
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SectionStudio} \
"The Android developer environment to design and develop your app for \
Android."
!ifdef BUNDLE_SDK
!insertmacro MUI_DESCRIPTION_TEXT ${SectionSdk} \
"The collection of Android platform APIs, tools and utilities that enables \
you to debug, profile, and compile your app."
!endif
!insertmacro MUI_DESCRIPTION_TEXT ${SectionAvd} \
"A preconfigured and optimized Android Virtual Device for app testing on \
the emulator. (Recommended)"
!insertmacro MUI_DESCRIPTION_TEXT ${SectionHaxm} \
"A hardware-assisted virtualization engine (hypervisor) which speeds up \
Android emulation on your development computer. (Recommended)"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
!insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${UNSectionStudio} \
"The Android developer environment to design and develop your app for \
Android."
!insertmacro MUI_DESCRIPTION_TEXT ${UNSectionSdk} \
"The collection of Android platform APIs, tools and utilities that enables \
you to debug, profile, and compile your app."
!insertmacro MUI_DESCRIPTION_TEXT ${UNSectionHaxm} \
"A hardware-assisted virtualization engine (hypervisor) which speeds up \
Android emulation on your development computer. (Recommended)"
!insertmacro MUI_DESCRIPTION_TEXT ${UNSectionUserSettings} \
"A folder that contains your saved Android Virtual Devices (AVDs), Android \
SDK caches, and, potentially, app signing keystores."
!insertmacro MUI_UNFUNCTION_DESCRIPTION_END
# ---------- Functions ---------------------------------------
# Macro which searches the user's computer for Java. Set CUSTOM_PATH to "" if you don't
# need to search a custom location.
# When finished, either $s_JdkPath will be set with the correct JDK base directory or it
# will be set to an empty string.
!macro FIND_JDK CUSTOM_PATH
StrCpy $s_JdkPath ""
# save user variables
Push $0 # find_java error code
Push $1 # find_java path (will be path to java.exe within a JDK)
Push $2 # find_java command line args
StrCpy $2 "-min 1.7 -error -jdk"
${If} "${CUSTOM_PATH}" != ""
StrCpy $2 "$2 -path ${CUSTOM_PATH}"
${EndIf}
nsExec::ExecToStack "$s_FindJavaExe $2"
Pop $0 # 0 on success, otherwise java.exe was not found.
Pop $1 # This is the Java path or an error string.
${If} $0 == 0
StrCpy $s_JdkPath $1
# FindJava returns JDK base plus "bin\java.exe"; remove the last part
# Note: The following string replace is case insensitive, so no need to
# worry about calling to-lower on JdkPath first
${StrRep} $s_JdkPath $s_JdkPath "\bin\java.exe" ""
${EndIf}
Pop $2 # restore user variables
Pop $1
Pop $0
!macroend
# Elevate the installer from user to admin priveleges, passing along some values
# from one process to the other via a temporarily created file.
!macro ELEVATE_PROCESS
# Hand off data from the user account to the admin account using the HKCU
# (Current User) registry
${IfNot} ${UAC_IsAdmin}
FileOpen $R0 ${USER_ADMIN_HANDOFF_FILE} w
FileWriteUTF16LE $R0 ${DEFAULT_SDK_PATH}
FileWriteUTF16LE $R0 "$\r$\n"
FileWriteUTF16LE $R0 ${ANDROID_USER_SETTINGS}
FileClose $R0
SetFileAttributes ${USER_ADMIN_HANDOFF_FILE} HIDDEN
${Else}
FileOpen $R0 ${USER_ADMIN_HANDOFF_FILE} r
FileReadUTF16LE $R0 $s_DefaultSdkPath
FileReadUTF16LE $R0 $s_UserSettingsPath
FileClose $R0
Delete ${USER_ADMIN_HANDOFF_FILE}
${If} $s_DefaultSdkPath != ""
# FileReadUTF16LE includes the newline (\r\n) in the read, so remove it.
StrCpy $s_DefaultSdkPath $s_DefaultSdkPath -2
${EndIf}
# Fail-safe in case values couldn't get read in for some reason
${If} $s_DefaultSdkPath == ""
StrCpy $s_DefaultSdkPath ${DEFAULT_SDK_PATH}
${EndIf}
${If} $s_UserSettingsPath == ""
StrCpy $s_UserSettingsPath ${ANDROID_USER_SETTINGS}
${Endif}
${EndIf}
uac_tryagain:
!insertmacro UAC_RunElevated # See UAC.nsh for documentation on return values
${Switch} $0
${Case} 0
${If} $1 = 1
# We are the user script, and we successfully elevated ourselves to the
# admin installer, which did all the real work. (This case is hit after
# the admin installer has finished)
Quit
${ElseIf} $3 <> 0
# We are already admin - we must be the spawned, elevated process. Continue!
Goto uac_success
${ElseIf} $1 = 3
# Somehow the user simply chose another non-admin account. Try again?
MessageBox MB_YESNO|MB_ICONEXCLAMATION "You must choose an account with administrative privileges. Try again?" \
/SD IDNO IDYES uac_tryagain IDNO 0
${EndIf}
${Break}
# If here, something went wrong. Fall to the next case to show the abort message.
${Case} 1223
MessageBox MB_ICONSTOP "The installer could not request administrative privileges and must abort."
${Break}
${Case} 1062
MessageBox MB_ICONSTOP "Logon service not running, which is needed to request administrative privileges, and the installer must abort."
${Break}
${Default}
MessageBox MB_ICONSTOP "Unable to elevate [error: $0]"
${Break}
${EndSwitch}
# Normally, we delete the handoff file right after being elevated to
# admin mode. However, if the user can't elevate to admin mode for some
# reason, we still need to clean this up.
Delete ${USER_ADMIN_HANDOFF_FILE}
Quit
uac_success:
Delete ${USER_ADMIN_HANDOFF_FILE}
SetShellVarContext all
!macroend
# Installer functions
Function .onInit
!ifdef UNINSTALL_BUILDER
System::Call "kernel32::GetCurrentDirectory(i ${NSIS_MAX_STRLEN}, t .r0)"
CreateDirectory "$0\uninstaller"
WriteUninstaller "$0\uninstaller\uninstall.exe"
MessageBox MB_OK "Uninstaller was built in $0\uninstaller" /SD IDOK
ExecShell "open" "$0\uninstaller"
Quit
!endif
!insertmacro STOP_STUDIO_PROCESS
!insertmacro ELEVATE_PROCESS
InitPluginsDir
# A useful property of PLUGINSDIR is that it's a temp directory that is automatically deleted
# after the installer runs. We'll load additional dependencies into there.
SetOutPath $PLUGINSDIR
${If} ${RunningX64}
SetRegView 64
${EndIf}
Call s_QuerySystemMemory
${If} $s_SystemMemoryGB < 1
!insertmacro EXCLUDE_SECTION ${SectionHaxm}
${EndIf}
!ifndef DRY_RUN
# Prepare find_java dependencies and look for Java
${If} ${RunningX64}
StrCpy $s_FindJavaExe "$PLUGINSDIR\${FIND_JAVA_EXE_64}"
${Else}
StrCpy $s_FindJavaExe "$PLUGINSDIR\${FIND_JAVA_EXE_32}"
${EndIf}
File /r "dependencies\*" # Dependencies contain find_java .exes
!insertmacro FIND_JDK ""
!insertmacro PREPARE_HAXM_INSTALLER
!insertmacro CAN_INSTALL_HAXM $R0
${If} $R0 == 0
!insertmacro EXCLUDE_SECTION ${SectionHaxm}
${Endif}
!endif # DRY_RUN
StrCpy $s_StudioPath "${DEFAULT_STUDIO_PATH}"
!ifdef BUNDLE_SDK
StrCpy $s_SdkPath $s_DefaultSdkPath
!endif # BUNDLE_SDK
# HACK: NSIS always defaults to "Program Files (x86)". However, we provide
# both 32-bit and 64-bit .exes, so we always want to install into
# "Program Files" regardless of OS type.
# See also: http://sourceforge.net/p/nsis/bugs/843/
${If} ${RunningX64}
# "C:\Program Files (x86)\blah" -> "C:\Program Files\blah"
${StrRep} $s_StudioPath $s_StudioPath $PROGRAMFILES $PROGRAMFILES64
${EndIf}
FunctionEnd
# Uninstaller functions
Function un.onInit
!insertmacro STOP_STUDIO_PROCESS
InitPluginsDir # See onInit for why we use PLUGINSDIR as a temp directory
SetOutPath $PLUGINSDIR
${If} ${RunningX64}
SetRegView 64
${EndIf}
StrCpy $s_StudioPath $INSTDIR # $INSTDIR is set to cwd
ReadRegStr $s_SdkPath HKLM "${REGKEY}" SdkPath
ReadRegStr $s_InstallSdk HKLM "${REGKEY}" InstallSdk
ReadRegStr $s_InstallHaxm HKLM "${REGKEY}" InstallHaxm
ReadRegStr $s_UserSettingsPath HKLM "${REGKEY}" UserSettingsPath
# If we weren't the ones who installed the SDK in the first place, don't
# recommend uninstalling it by default
${If} $s_InstallSdk != 1
${UnselectSection} ${UNSectionSdk}
${Endif}
# If we weren't the ones who installed HAXM in the first place, don't
# recommend uninstalling it by default.
${If} $s_InstallHaxm != 1
${UnselectSection} ${UNSectionHaxm}
${EndIf}
# Don't uninstall user settings by default
${UnselectSection} ${UNSectionUserSettings}
!ifndef DRY_RUN
# Exclude sections we can't or don't need to uninstall
IfFileExists $s_SdkPath skip_exclude_sdk_section 0
!insertmacro EXCLUDE_SECTION ${UNSectionSdk}
skip_exclude_sdk_section:
IfFileExists $s_UserSettingsPath skip_exclude_settings_section 0
!insertmacro EXCLUDE_SECTION ${UNSectionUserSettings}
skip_exclude_settings_section:
!insertmacro PREPARE_HAXM_INSTALLER
!insertmacro IS_HAXM_INSTALLED $R0
${If} $R0 == 0
!insertmacro EXCLUDE_SECTION ${UNSectionHaxm}
${Endif}
!endif # DRY_RUN
IfSilent 0 skip_disable_sections
# The silent uninstaller is called by the installer when we want to
# replace an existing version of Android Studio by removing it. So, only
# remove Android Studio and nothing else!
${UnselectSection} ${UNSectionSdk}
${UnselectSection} ${UNSectionHaxm}
${UnselectSection} ${UNSectionUserSettings}
skip_disable_sections:
!insertmacro MUI_STARTMENU_GETFOLDER Application $s_StartMenuGroup
FunctionEnd
# Ask the system for how much memory it has available. When finished,
# the variables $s_SystemMemoryMB and $s_SystemMemoryGB will be initialized
Function s_QuerySystemMemory
# We will need to use variables $0 through $9, so save away any existing values.
Push $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
Push $8
Push $9
# Call GlobalMemoryStatusEx using the System plugin.
# For more info: http://nsis.sourceforge.net/Docs/System/System.html
System::Alloc 64
Pop $0
# GlobalMemoryStatusEx requires the first parameter to be the size
# of the whole structure. Everything else is zeroed out.
System::Call "*$0(i 64, i 0, l 0, l 0, l 0, l 0, l 0, l 0, l 0)"
System::Call "Kernel32::GlobalMemoryStatusEx(i r0)" # Read status into $0
System::Call "*$0(i.r1, i.r2, l.r3, l.r4, l.r5, l.r6, l.r7, l.r8, l.r9)"
# Machine's physical memory value (in bytes) is the third parameter. See MSDN:
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx
System::Int64Op $3 / 1048576 # 1024 * 1024
Pop $s_SystemMemoryMB
System::Int64Op $s_SystemMemoryMB / 1024
Pop $s_SystemMemoryGB
System::Free $0
# Restore old values
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
# Function invoked by MUI_FINISHPAGE_RUN
Function s_StartApp
!ifndef DRY_RUN
# ExecShell sets the CWD using $OUTDIR, which in this context is the
# StartMenu>Shortcuts folder.
# We change it to where studio.exe is actually located
# for this invocation and then restore it.
Push $OUTDIR
SetOutPath $s_StudioPath
${If} ${RunningX64}
StrCpy $R0 "$s_StudioPath\bin\${EXE_NAME_64}"
${Else}
StrCpy $R0 "$s_StudioPath\bin\${EXE_NAME_32}"
${EndIf}
!insertmacro UAC_AsUser_ExecShell "" "$R0" "" "" ""
Pop $OUTDIR
!endif # DRY_RUN
FunctionEnd
# Check whether directory is empty: use FindFirst/FindNext,
# skipping the "." and ".." directories.
# Return 1 (true) if empty and 0 (false) if not empty.
Function s___isEmptyDir
Exch $0 # $0 = Get dir
Push $1
Push $2
StrCpy $2 1 # result is 1/true by default (empty)
FindFirst $0 $1 "$0\*.*" # $0 <= find handle, $1 <= first match,
${DoWhile} $1 != "" # Find returns "" when done
${If} $1 != "."
${AndIf} $1 != ".."
StrCpy $2 0 # result is false (not empty)
${Break}
${Endif}
FindNext $0 $1
${Loop}
ClearErrors
FindClose $0
StrCpy $0 $2 # $0 is result (0 or 1)
Pop $2
Pop $1
Exch $0
FunctionEnd
!macro s__IsEmptyDir VAR DIR
Push ${DIR}
call s___isEmptyDir
Pop ${VAR}
!macroend
!define s_IsEmptyDir "!insertmacro s__IsEmptyDir"
!macro ConfirmUninstallPath PATH OUT_VAR
MessageBox MB_YESNO|MB_ICONEXCLAMATION \
"This will remove ALL of the program files under$\r$\n\
$\r$\n\
${PATH}$\r$\n\
$\r$\n\
and cannot be undone. Are you sure you wish to continue?" \
/SD IDYES IDYES yes IDNO no
yes:
StrCpy ${OUT_VAR} 1
Goto done
no:
StrCpy ${OUT_VAR} 0
Goto done
done:
!macroend
!define ConfirmUninstallPath '!insertmacro ConfirmUninstallPath'
Function fnc_UninstallPreviousPage_ShowIfNecessary
!ifndef DRY_RUN
# Offer to remove a currently installed version of Studio if found
ReadRegStr $R0 HKLM "${REGKEY}" Path
${If} $R0 != ""
StrCpy $R1 "$R0\uninstall.exe"
IfFileExists $R1 show_uninstall_page 0
${Endif}
Abort # Skip uninstall page
!else
StrCpy $R0 "C:\Dummy Path\Android Studio"
!endif # DRY_RUN
show_uninstall_page:
Push $R0
Call fnc_UninstallPreviousPage_SetTargetPath
Call fnc_UninstallPreviousPage_Show
FunctionEnd
Function func_UninstallPreviousPage_Leave
!ifndef DRY_RUN
${NSD_GetState} $hCtl_UninstallPreviousPage_CheckUninstall $R0
${If} $R0 == ${BST_CHECKED}
${NSD_GetText} $hCtl_UninstallPreviousPage_TextPath $R1
${ConfirmUninstallPath} $R1 $R2
${If} $R2 == 0
Abort
${Endif}
StrCpy $R3 "$R1\uninstall.exe"
# _?=... causes the uninstaller to run directly instead of in the
# background. If we don't do this, ExecWait won't work.
ExecWait '"$R3" /S _?=$R1'
Delete $R3
RmDir $R1 # Should be empty after the uninstaller is removed
${EndIf}
!endif
FunctionEnd
Function fnc_FindJavaPage_ShowIfNecessary
# Skip this page if the JDK path is already set
${If} $s_JdkPath != ""
Abort
${EndIf}
Call fnc_FindJavaPage_Show
FunctionEnd
Function fnc_FindJavaPage_InitializeControls # Called in FindJavaPage.nsdinc
${If} ${RunningX64}
StrCpy $R0 ${JDK_EXE_64}
${Else}
StrCpy $R0 ${JDK_EXE_32}
${EndIf}
${NSD_SetText} $hCtl_FindJavaPage_LinkDownloadJdk $R0
FunctionEnd
Function fnc_FindJavaPage_LinkDownloadJdk_OnClick # Called in FindJavaPage.nsdinc
ExecShell "open" ${JDK_LINK}
FunctionEnd
Function fnc_FindJavaPage_Leave
!ifndef DRY_RUN
${NSD_GetText} $hCtl_FindJavaPage_DirRequestJdkPath_Txt $R0
!insertmacro FIND_JDK $R0
${If} $s_JdkPath == ""
MessageBox MB_OK|MB_ICONEXCLAMATION 'Sorry, we still could not detect a valid JDK, which we need to proceed.$\r$\n \
$\r$\n \
If setting your JDK path manually, make sure you have browsed to a parent directory that contains a "bin\java.exe" whose \
version reports 1.7 or higher when you run "java.exe -version".'
Abort
${EndIf}
!endif # DRY_RUN
FunctionEnd
Function fnc_AndroidSdkPage_ShowIfNecessary
!ifndef BUNDLE_SDK
Abort # Skip this page if this installer doesn't bundle an SDK
!endif
# Skip this page if the user is installing the latest SDK
${If} $s_InstallSdk != 0
Abort
${EndIf}
Call fnc_AndroidSdkPage_Show
FunctionEnd
Function fnc_AndroidSdkPage_InitializeControls # Called in AndroidSdkPage.nsdinc
IfFileExists $s_SdkPath 0 skip_set_sdk_text
${NSD_SetText} $hCtl_AndroidSdkPage_DirRequestUseExisting_Txt $s_SdkPath
skip_set_sdk_text:
FunctionEnd
# Test if a target directory is an Android SDK. If it is, OUT_VAR will be set to
# 1, else 0.
!macro IS_SDK SDK_DIR OUT_VAR
StrCpy ${OUT_VAR} 0
IfFileExists "${SDK_DIR}\tools\android.bat" valid_sdk invalid_sdk
valid_sdk:
StrCpy ${OUT_VAR} 1
invalid_sdk:
!macroend
!define IS_SDK "!insertmacro IS_SDK"
Function fnc_AndroidSdkPage_Leave
${NSD_GetState} $hCtl_AndroidSdkPage_RadioInstallLatest $R0
${If} $R0 == ${BST_CHECKED}
StrCpy $s_InstallSdk 1
${Else}
StrCpy $s_InstallSdk 0
${NSD_GetText} $hCtl_AndroidSdkPage_DirRequestUseExisting_Txt $R0
${IS_SDK} $R0 $R1 # $R0 is the directory we're testing. $R1 will be set to 1 if it's vaild.
${If} $R1 == 0
MessageBox MB_OK|MB_ICONEXCLAMATION "Sorry, the selected SDK path is invalid." /SD IDOK
Abort
${Endif}
StrCpy $s_SdkPath $R0
${EndIf}
FunctionEnd
# Given an input path, return a path that's non-empty, by appending numbers to the end.
# The path will be returned as-is if it is already empty.
#
# To use:
# Push $pathIn
# Call s_computeEmptyDir
# Pop $pathOut # You can use $pathIn here again to overwrite it
Function s___computeEmptyDir
Exch $0 # Get directory to check
Push $1 # s_IsEmptyDir return value
# Check whether that install directory is empty. If not, compute a new value.
${s_IsEmptyDir} $1 $0
${If} $1 == 0
Push $R0 # Integer value which we'll append to DIR, like DIR1, DIR2, etc...
Push $R1 # Copy of $0 (original path) plus a numeric value
StrCpy $R0 0
${Do}
IntOp $R0 $R0 + 1
StrCpy $R1 "$0$R0"
${s_IsEmptyDir} $1 $R1
${LoopUntil} $1 != 0
StrCpy $0 $R1
Pop $R1
Pop $R0
${Endif}
Pop $1
Exch $0 # Put output directory on top of the stack
FunctionEnd
!macro s__computeEmptyDir PATH
Push ${PATH}
Call s___computeEmptyDir
Pop ${PATH}
!macroend
!define s_computeEmptyDir "!insertmacro s__computeEmptyDir"
# Called when entering the Components page.
Function s_ComponentsPagePre
!ifdef BUNDLE_SDK
# Restore the SDK section selection if the user previously expressed
# interest in installing it (and are now coming back to this page).
# See also s_ComponentsPageLeave, which sets the flag.
${If} $s_InstallSdk != 0
${SelectSection} ${SectionSdk}
${Else}
${UnselectSection} ${SectionSdk}
${EndIf}
!endif # BUNDLE_SDK
FunctionEnd
# Called when leaving the Components page.
Function s_ComponentsPageLeave
!ifdef BUNDLE_SDK
# Minor hack alert: We ALWAYS want to install this installer's SDK, either
# to the directory the user specified, or to a temporary location that
# Android Studio's first run experience can make use of. Therefore, even
# if a user says they don't want to install the SDK, we have to switch the
# flag on behind their back anyway. The $s_InstallSdk flag will modify the
# behaviour of the SDK section.
SectionGetFlags ${SectionSdk} $R0
IntOp $s_InstallSdk $R0 & ${SF_SELECTED}
${SelectSection} ${SectionSdk}
!else
StrCpy $s_InstallSdk 0
!endif # BUNDLE_SDK
SectionGetFlags ${SectionHaxm} $R0
IntOp $s_InstallHaxm $R0 & ${SF_SELECTED}
FunctionEnd
# Called when entering the Android License page.
Function s_AndroidLicensePagePre
!ifndef BUNDLE_SDK
Abort
!endif # BUNDLE_SDK
${If} $s_SkipAndroidLicense == 1
Abort
${Endif}
FunctionEnd
# Called when leaving the Android License page.
Function s_AndroidLicensePageLeave
StrCpy $s_SkipAndroidLicense 1
FunctionEnd
# Called when entering the Intel License page.
Function s_IntelLicensePagePre
${If} $s_SkipIntelLicense == 1
Abort
${Endif}
# No need to show the Intel license if we're not installing HAXM
SectionGetFlags ${SectionHaxm} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
${If} $R0 == 0
Abort
${EndIf}
FunctionEnd
# Called when leaving the Intel License page.
Function s_IntelLicensePageLeave
StrCpy $s_SkipIntelLicense 1
FunctionEnd
Function fnc_InstallDirsPage_InitializeControls # Called in InstallDirsPage.nsdinc
${s_computeEmptyDir} $s_StudioPath
${NSD_SetText} $hCtl_InstallDirsPage_DirRequestStudio_Txt $s_StudioPath
${If} $s_InstallSdk != 0
${s_computeEmptyDir} $s_SdkPath
${NSD_SetText} $hCtl_InstallDirsPage_DirRequestSdk_Txt $s_SdkPath
${Else}
ShowWindow $hCtl_InstallDirsPage_GroupSdk ${SW_HIDE}
ShowWindow $hCtl_InstallDirsPage_LabelSdk ${SW_HIDE}
ShowWindow $hCtl_InstallDirsPage_DirRequestSdk_Txt ${SW_HIDE}
ShowWindow $hCtl_InstallDirsPage_DirRequestSdk_Btn ${SW_HIDE}
${EndIf}
FunctionEnd
Function fnc_InstallDirsPage_Leave
${NSD_GetText} $hCtl_InstallDirsPage_DirRequestStudio_Txt $s_StudioPath
${s_IsEmptyDir} $0 $s_StudioPath
${If} $0 == 0
MessageBox MB_OK|MB_ICONINFORMATION "Please select an empty folder to install Android Studio." /SD IDOK
Abort
${Endif}
${If} $s_InstallSdk != 0
${NSD_GetText} $hCtl_InstallDirsPage_DirRequestSdk_Txt $s_SdkPath
${IS_SDK} $s_SdkPath $R1 # $R1 will be set to 1 if an SDK is already there
${If} $R1 == 1
StrCpy $s_InstallSdk 0
Goto endOfBlock
${Endif}
${s_IsEmptyDir} $0 $s_SdkPath
${If} $0 == 0
MessageBox MB_OK|MB_ICONINFORMATION "Please select an empty folder to install the Android SDK." /SD IDOK
Abort
${Endif}
${StrContains} $R1 $s_SdkPath $s_StudioPath
${If} $R1 != 0
MessageBox MB_OK|MB_ICONEXCLAMATION \
"You are attempting to install the Android SDK inside your Android Studio installation.$\r$\n \
$\r$\n \
Updates to Android Studio will not work in this configuration. Please select a valid installation path."
Abort
${Endif}
# Make sure the user didn't put their SDK under Program Files
StrCpy $R0 $PROGRAMFILES
${If} ${RunningX64}
StrCpy $R0 $PROGRAMFILES64
${EndIf}
${StrContains} $R1 $s_SdkPath $R0
${If} $R1 != 0
MessageBox MB_YESNO|MB_ICONQUESTION \
"Android Studio periodically updates your SDK to make sure your files are up to date. \
To avoid getting errors when updating, we recommend installing your SDK into a user directory with read/write access.$\r$\n \
$\r$\n \
Do you want to update the SDK installation path?" IDYES updateSdkPath IDNO ignoreWarning
updateSdkPath:
StrCpy $s_SdkPath $s_DefaultSdkPath
${NSD_SetText} $hCtl_InstallDirsPage_DirRequestSdk_Txt $s_SdkPath
Abort
ignoreWarning:
${Endif}
endOfBlock:
${EndIf}
FunctionEnd
Function fnc_HaxmPage_ShowIfNecessary
# Skip this page if the user deselected the HAXM component
SectionGetFlags ${SectionHaxm} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
${If} $R0 == 0
Abort
${EndIf}
Call fnc_HaxmPage_Show
FunctionEnd
Function fnc_HaxmPage_InitializeControls # Called in HaxmPage.nsdinc
Push $s_SystemMemoryMB
Call fnc_HaxmPage_SetSystemMemory
FunctionEnd
# Called when leaving the "Confirm Uninstall" page
Function un.s_ConfirmPageLeave
${ConfirmUninstallPath} $s_StudioPath $R0
${If} $R0 == 0
Abort
${Endif}
FunctionEnd