Presentation is loading. Please wait.

Presentation is loading. Please wait.

Android Application Framework

Similar presentations


Presentation on theme: "Android Application Framework"— Presentation transcript:

1 Android Application Framework
Chapter 3 Android Application Framework

2 Android Application Framework

3 Android Application Framework
何謂生命週期?應用程式元件都具有生命週期—從Android產生回應一個Intent物件開始,到實際被釋放為止。 一般情況Android應用程式是由以下四種元件所組成的: 活動(Activity) 服務(Service) 廣播接收器(Broadcast Receiver) 內容提供器(Content Provider)

4 Android Application Framework
活動(Activity) 一般所指的活動是使用者介面。一支應用程式可能有一個或以上的活動存在,每個活動也都會有自己的View。 所有的活動在系統裡由活動堆疊所管理,當一個新的活動被執行後,它將會被放置到堆疊的最頂端,並且變成"running activity",而先前的活動原則上還是會存在於堆疊中,但它此時不會是在前景的情況,除非新加入的活動離開。

5 Android Application Framework
服務(Service) 服務是在背景長時間運行的應用元件,不和使用者直接進行互動。 例如:某服務可能在後台播放音樂,而用於在執行其他的操作,或者它透過網絡抓取資料或者執行某些計算,將結果提供給活動。

6 Android Application Framework
廣播接收器(Broadcast Receiver) 廣播接收器負責接受和回應通知,很多通知源自於系統所發送的,例如:發送時區變換的通知,電池電量不足,或使用者改變語言設置。 應用程式也可以發出廣播通知,舉例來說,通知其它應用程式,資料已下載完畢,可供使用。 應用程式可以擁有任意數量的廣播接收器來接收任何的通知。另外也可以啟動活動去回應接收到的通知,或利用通知管理器(NotificationManager)來通知使用者。

7 Android Application Framework
內容管理器(Content Provider) 內容管理器將應用程式資料組合成特定的集合供其它應用程式使用。資料可以是儲存在檔、SQLite資料庫,或是其它任何使用者可以存取資料的地方。 內容管理器繼承於內容管理器基礎類別,並實作一組標準的方法,使應用程式可以檢索和儲存它控制的資料。 應用程式不是直接呼叫這些實作方法。而是透過內容解析器(ContentResolver)對象呼叫方法。內容解析器能夠通知任何的內容管理器,並可以參與這些內容管理器行程間的管理。

8 Android Application Framework
程式的生命週期(Life Cycle) 活動 一個Activity基本上有三個生命狀態: active或running Paused Stop 當一個Activity處於Pause或Stop的狀態時,系統可以要求Activity結束或移除它,當它再度呈現在使用者面前時,要能完整的重新啟動及回復先前的狀態。 應用程式存在與否並非由應用程式所自行決定,而是由Android系統透過運行機制決定。 一個Activity基本上有三個生命狀態: 當一個Activity在螢幕的最上層時(系統堆疊中的最頂端),此Activity就是屬於active或running的狀態。 當一個Activity失去焦點(Focus)但還看得到它的畫面,那失去焦點的這個Activity則處在Paused的狀態,像這個Activity它還是存活著,並沒有從系統中消失(Activity本身所有的狀態及資料都還存在,也跟視窗管理程式Window Manager保持連繫著),像這種屬於Paused狀態的Activity,當系統的記憶體不夠用時,系統會自動判斷,把優先順序較低的Activity移除。 當一個Activity被其它的Activity完全遮蔽,被遮蔽Activity就是處於Stop的狀態,不過仍保有全部的狀態及資料,但因為已不再被使用者看見,所以它的畫面是被隱藏起來的(畫面不需要更新),當系統記憶體不足時,這種Stop狀態的Activity是最先被系統考慮拿來釋放記憶體的。

9 Life Cycle of Application
活動狀態間的切換包含了呼叫下列幾種方法: void onCreate(Bundle savedInstanceState) void onStart() void onRestart() void onResume() void onPause() void onStop() void onDestroy()

10 Life Cycle of Application
Activity Lifecycle(圖片來源:Android SDK Dev Guide)

11 Life Cycle of Application
活動的Entire Lifetime 一個活動的Entire Lifetime是由onCreate(Bundle)開始,直到onDestroy()結束。 一個活動可以把所有的資源設定寫在onCreate中,直到onDestroy()時,再釋放出來。 舉例來說,當需要一個執行緒在背景執行網路下載資料,這個執行緒就可以在onCreate()中建立起來,一直到onDestroy()再把執行緒釋放。

12 Entire Lifetime

13 Life Cycle of Application
活動的Visible Lifetime: 一個活動的Visible Lifetime則是指在onStart()到onStop()之間,稱為“可視生命週期”,在這段時間內,使用者可以在螢幕上看見Activity,但這個Activity不見得一定在前景跟使用者直接互動。 舉例來說:你可以在onStart()註冊一個BroadcastReceiver用來監控並改變你的UI,當使用者不想再看你所呈現的結果時,在onStop()移除註冊的roadcastReceiver。 onStart()跟onStop()可以在Activity在Visible及Hidden兩個狀態切換時多次被呼叫執行。

14 Visible Lifetime

15 Life Cycle of Application
活動的Foreground Lifetime: Foreground Lifetime則是指onResume()到onPause()之間,在這個時期的活動是在所有的活動的前面,並且直接跟使用者進行互動。 一個活動能很頻繁的在Resume及Pause這兩個狀態切換,所以在onResume()及onPause()中實作的程式應盡量精簡。

16 Foreground Lifetime

17 Life Cycle of Application
服務 在每一個包含服務元件的AndroidManifest.xml文件中,必須有一個相應的<service>宣告。 服務可以用兩種方式呼叫: 服務自行啟動和運行,直到某項操作停止或自行停止時。 它可被提供給對外使用者的介面所操作。用戶端與服務物件建立連接並呼叫服務。

18 Life Cycle of Application
服務 上述兩種模式不是完全分開的,且可以綁定一個被startService()啟動的服務。 這種情況下,stopService()不會停止服務,一直到最後一個綁定的連接關閉時。 與活動相似,服務也有一些生命週期方法,程式設計師可以實作它們去改變狀態,但方法比活動要少。 上述兩種模式不是完全分開的。可以綁定一個被startService()啟動的服務。 例如,一個背景音樂服務可以被一個Intent物件定義音樂播放,通過呼叫startService()啟動。隨後,使用者想操作一些控制或獲得正在播放的音樂資訊時,Activity可通過bindService()建立連接。 這種情況,stopService()不會停止服務,一直到最後一個綁定的連接關閉時。

19 Life Cycle of Application
Service Lifecycle (圖片來源:Android SDK Dev Guide)

20 Life Cycle of Application
服務的Entire Lifetime 服務的Entire Lifetime是在onCreate()開始,於onDestroy()結束。 類似活動,服務在onCreate()方法中進行初始化,在onDestroy()方法中釋放所有系統資源。 例如,音樂播放服務可能在onCreate()方法中建立音樂播放執行緒,在onDestroy()方法中停止執行緒。

21 Life Cycle of Application
服務的Active Lifetime 在呼叫startService()方法後,此方法被Intent對象指示去呼叫onStart() 方法。 音樂服務將分析這個Intent來確定播放什麼音樂,並開始播放。

22 Life Cycle of Application
廣播接收器 廣播接收器只有一個生命週期方法: void onReceive(Context curContext, Intent broadcastMsg) 當廣播消息到達接收者時,Android呼叫onReceive()方法,並傳遞保存著訊息的Intent對象。 當呼叫該方法時,廣播接收者被認為是active的。當onReceive()結束時,它就是inactive的。  擁有活動的廣播接收者行程,會被保護不被清除。但是只擁有inactive的廣播元件時,當系統認為記憶體應該被其他行程使用時,可以在任何時間被系統清除。 

23 Life Cycle of Application
廣播接收器 當與廣播元件頻繁互動時,會產生一些問題,因此,某些任務在獨立的執行緒中操作,與管理其他的用戶元件的主執行緒是分開的。 如果onReceive()產生執行緒然後返回,這個完整的行程,包括新產生的執行緒,將被判斷為inactive的,會被提報為將被清除的行程。 解決這個問題的辦法是為onReceive()啟動一個Service,讓Service接手這工作,因此系統會認為在行程中仍然有active的工作在進行。

24 Life Cycle of Application
行程與生命周期 Android系統會盡可能保存各個應用程式行程,但當記憶體不夠用時,系統需要移除較舊的行程。 為了判斷哪些行程該被保留,哪些行程該被清除,Android把每一個行程放到一個〝優先層次〞列表,元件的運行和狀態是基於這個〝優先層次〞列表。

25 Life Cycle of Application
Process and Lifecycle 該優先權分五層。下面的列表顯示優先權層次順序: 前景行程 可視行程 服務行程 背景行程 空行程 前景行程,是目前手機上正在顯示的程式畫面,由onCreate、onStart()、onResume()所呼叫的Activity都會程為前景行程。 可視行程,就是Activity視窗畫面變為透明時,但仍可被使用者看見的行程,行程保存著一個不在前景但對用戶來說還是可見的Actitivy(onPause()方法已經被呼叫), 待上一個Activity完成後再呼叫onResume()。例如:此Activity是一個對話方塊,允許之前的Activity在它下面顯示。可視行程是非常的重要,除非清除它可以保持所有的前景行程運行,否則將不會被清除。 服務行程,運行著某個已經被startService()方法啟動的服務,儘管服務行程並不可見,但服務行程通常執行用戶要求的任務(例如:正在背景中下載資料), 因此系統會保持它們的運行,除非是沒有足夠的記憶體空間讓他們與前景行程和可視行程同時運行。 背景行程,是保存著當前對使用者不可見的Activity(onStop()已經被呼叫)的行程。這些行程沒有直接影響使用者操作,可能會在任何時間被回收記憶體給予前景、可視和服務行程使用。 空行程,是沒有保存任何Activity應用程式元件的行程。維持此類行程的原因是做為一個提高下次需要保存在它們裡面運行的元件啟動速度的快取。 系統常常會清除這些行程,為了保持行程快取與底層的核心快取的平衡。

26 Life Cycle of Application
Android會基於擁有著當前活動的行程中,各元件重要性,儘量給予它最高級別。 運行服務的執行緒比運行背景活動的行程級別要高,一個活動需要開始執行一個長時間操作時,應啟動一個服務,而不是自行建立一個執行緒。 同樣的原因,廣播接收器也應該呼叫服務而不是將一個長時間操作放到自行建立的執行緒中處理。

27 Advantage of MVC Design Model
MVC(Model-View-Controller,模型-檢視-控制器模式)用於表示一種軟體架構模式 MVC把軟體分為三個基本部分: 模型(Model) 檢視(View) 控制器(Controller)

28 Advantage of MVC Design Model
圖片來源: MVC架構

29 Advantage of MVC Design Model
MVC架構起始於一個GUI(graphical user interface design patter)原型。 其目的是實作動態程式設計,使日後對於程式修改及擴展更加便利,並使某些程式碼可重複利用。 另外透過對複雜度的簡化,使程式結構更加直覺。 MVC架構起始於一個GUI(graphical user interface design patter,圖型使用者介面設計原型)原型,其目的是實作動態程式設計, 使日後對於程式修改及擴展更加便利,並使某些程式碼可重複利用。另外透過對複雜度的簡化,使程式結構更加直覺。 軟體系統透過對自身基本部份分離的同時也給予各部分應有的功能,如同一所大公司一樣,將工作區分做到專業化,專業人員可以透過自身的專長分組: Controller - 程式設計師編寫程式架構及功能(例如:實作演算法)。 View - 美工或UI設計人員進行圖形介面設計及美化。 Model - 資料庫人員進行資料管及資料庫設計。 在Android中,程式設計師利用Java撰寫程式邏輯及架構,美工設計則使用xml來撰寫使用者介面,資料庫人員則針對SQL資料庫進行設計及優化。

30 Application Framework
src:放置主程式、class的地方 gen:放系統資源檔、元件存放的地方,當中的R.java是由 Android Development Kit (ADK)所自動產生的資源索引檔(resource index),R.java是根據main.xml (在 res.layout中) 所自動產生,並不是由程式設計師編寫的,一般來說不需要修改此檔案。 Android 1.6:放置Android Library的地方 (此處使用1.6版)。 res: 外部資源檔存放的位置,可以設定文字、圖片、XML等, drawable : 存放 icon圖片,像是*.png, *.jpg, *.gif等等。 layout : 存放畫面設定檔,使用者介面佈局檔。 values : 存放常數資源檔,定義文字、陣列、顏色尺寸等等。 AndroidManifest.xml:應用程式定義檔,定義應用程式要提供的內容和動作 如圖所示,將套件瀏覽器中的HelloWorld專案展開,可以發現有多層的樹狀結構。

31 Android Manifest.xml

32 Android Manifest.xml Android Manifest定義檔是一個用來描述應用程式「整體資訊」的設定檔。

33 Android Manifest.xml 在圖中的Android Manifest設定畫面中,顯示了許多資訊,在Links的選項也有Applications、Permissions、Instrumentation、XML source、Documentation等選項,點選XML Source即可直接修改原始碼。

34 Android Manifest.xml 此定義檔的重點就是其中的目標過濾器(Intent Filters),這些過濾器描述了什麼時間及情況下讓Activity啟動。 除了描述應用程式的活動、內容管理器、服務和Intent接收器,也可以在AndroidManifest.xml檔中指定權限和安全控制測試。 此定義檔的重點就是其中的目標過濾器(Intent Filters),這些過濾器描述了什麼時間及情況下讓Activity啟動。 當一個Activity(或是OS)想要執行一個動作,例如:打開網頁或是通訊錄選取清單,它將會建立一個Intent對象, 該對象包含了很多描述,描述了想做什麼操作,想處理什麼資料(包含資料的類型),及一些其它的訊息。 Android將Intent對象中的訊息與所有應用的目標過濾器比較,找到一個最能恰當處理使用者要求的資料和動作的Activity。 除了描述應用程式的活動(Activities),內容管理器(Content Providers),服務(Services),和Intent接收器(Intent Receivers), 你也可以在AndroidManifest.xml檔中指定權限和安全控制測試。

35 Android Manifest.xml 需要注意的一些通用事項:
幾乎所有的AndroidManifest.xml檔都會在第一個元素中包含一個命名空間xmlns:android=" 該定義使得標準Android屬性可在該檔中可使用,這些屬性提供了檔中的xml元素大部分資料。 大多數的manifests包含一個<application>元素,該元素定義了這個程式內所有應用層面上可用的元件和屬性。 所有需要可以從應用程式啟動器(Program Launcher)中呈現給使用者的高層應用都至少要包括一個活動(Activity)元件,它用來支援MAIN action 和顯示在LAUNCHER目錄中。

36 Android Manifest.xml <manifest>為文件根節點,描述了程式的所有內容,在其節點下面內可放置各種標籤:
<uses-permission> <permission> <instrumentation> <application> <manifest> 文件根節點。描述了程式的所有內容,在其節點下面內可放置各種標籤。 <uses-permission> 請求一個安全授權,你的程式必須被授予該權限才能正確的操作。一個manifest可以包含零個或多個這樣的節點。 <permission> 宣告一個安全授權,它用來限制哪些應用可以使用程式的元件和功能。一個manifest可以包含零個或多個這樣的節點。 <instrumentation> 宣告一個instrumentation元件可用於測試這一個或別的包的代碼。一個manifest可以包含零個或多個這樣的節點。 <application> 宣告應用程式內應用級別元件的根節點。該節點能夠描述應用程式的全域屬性,例如標籤、圖標、主題、需要的權限等等。一個manifest可以包含零個或一個這樣的節點(多個application節點是不允許的)。 在該節點下,可以包含下列零個或多個以下每個元件的宣高: <activity> 活動(Activity)是應用程式與使用者互動的最主要機制,當一個應用程式運行的時候,用戶看到的第一個畫面就是Activity。 <intent-filter> 以一個Intent Filter的形式宣告元件所支持的特定Intent值。除了可以在此元素下指定的各種值,也可以在此對屬性設定以支援標籤(label)、圖標(icon)和所描述動作(action)的其它資訊。 <action> 該元件支援的Intent action。 <category> 該元件支援的Intent目錄(Intent category)。 <data> 該元件支援的Intent data MIME type、Intent data URI scheme、Intent data URI authority或Intent data URI path。你也可把一個或多個meta-data 與活動(activity)關聯,其它使用者可以透過這些meta-dada取得關於這 個活動的任意訊息。 <meta-data> 向Activity增加新的meta data,使用者可以通過ComponentInfo.metaData獲取該數據。 <receiver> 一個BroadcastReceiver可以使應用程式接收資料變化和行為發生的通知,即使這個應用程式沒有在運行也同樣可以。與Activity標籤一樣,你可以選擇包含一個或多個該receiver支援元素或值。 <service> 服務(Service)是一個在後台可以運行任意長時間的組件。 同activity 標籤一樣, 你可以選擇包含一個或多個該服務支援元素或值。 <provider> 組件管理器(ContentProvider)用來管理持久數據和向其它應用發佈數據的組件。你也可以按照活動的(activity's)中描述附加一個或多個 <meta-data> 值。

37 Android Manifest.xml 在<application>中可以有零個或多個以下的元件:
<activity> <intent-filter> <action> <category> <data> <meta-data> <receiver> <service> <provider>

38 Android Resource File Design

39 Android Resource File Design
多國語系、文字資源檔- strings.xml 顏色設定資源檔 - colors.xml 尺寸定義資源檔 - dimens.xml 樣式資源檔 - styles.xml 視窗佈局資源檔 - layout\main.xml 動畫資源檔 - anim.xml 圖檔資源目錄 - drawable 本節將介紹所有關於Android的資源檔設計方式。 多國語系、文字資源檔- strings.xml 顏色設定資源檔 - colors.xml 尺寸定義資源檔 - dimens.xml 樣式資源檔 - styles.xml 視窗佈局資源檔 - layout\main.xml 動畫資源檔 - anim.xml 圖檔資源目錄 - drawable

40 多國語系、文字資源檔 多國語系、文字資源檔( strings.xml) 一開始從最常使用的文字資源檔strings.xml學習
所有的XML文件開頭都是<?xml>,裡面可以定義xml版本及編碼。接著宣告<resources>標籤,就可在裡面使用<string>標籤定義文字字串。 <string>標籤裡面則使用name屬性定義字串變數名稱,在標籤之間可加上自串內容。 另外<string>標籤之間也可加上<b>、<i>、<u>,為文字加上粗體、斜體、底線的效果。

41 Android Resource File Design
可以在JAVA原始檔中使用這些變數: 用法:R.string.字串名稱 範例:CharSequence hello = getString(R.string.hello); 在JAVA原始檔中使用,使用方式如下圖3.10所示。 R.string.字串名稱 例如:CharSequence hello = getString(R.string.hello);

42 Android Resource File Design
也可以讓XML資源文件使用字串資源: @string/字串名稱

43 Android Resource File Design
若要支援多國語戲程式的設計,就為各種語言建立不同的目錄。 範例:values-cht繁體中文、values-en英文、values-jp日文……等等。

44 Android Resource File Design

45 Colors.xml 顏色設定資源檔 (colors.xml) 在Android中的顏色代碼類似網頁中的顏色代碼,都是採用16進位的方式
Android支援的顏色語法有:#RGB、#ARGB、#RRGGBB、#AARRGGBB四種

46 Colors.xml 以#AARRGGBB作為範例: 以#AARRGGBB作為範例

47 Colors.xml 在res/values/底下新增colors.xml,就可以編輯並使用<color>標籤設定資源檔。
先設定<color>標籤變數名稱,接在設定black的顏色代碼。

48 Colors.xml 同樣地,當設定完資源檔後,如果要被拿來使用的話,可使用與文字資源檔一樣的方法來呼叫。 在JAVA原始檔中使用

49 Colors.xml 在JAVA原始檔中使用 用法:R.color.顏色常數名稱
範例:getResources().getColor(R.color.black);

50 Colors.xml 在XML文件中使用 用法:@color/顏色變數名稱

51 Colors.xml 另外也可在colors.xml中使用<drawable>圖形顏色標籤。

52 Colors.xml 在JAVA原始檔中使用 用法:R.drawable.顏色變數名稱
範例:Drawable blueColor = getResources.getDrawable(R.drawable.blue);

53 Colors.xml 在XML文件中使用 用法:@drawable/顏色變數名稱

54 Dimens.xml 尺寸定義資源檔 - dimens.xml
首先於res/values中新增dimens.xml,此檔案可針對字串個別設定字型大小,像是px、in、mm、pt、dp、dip、sp等等尺寸。

55 Dimens.xml 尺寸定義資源檔(dimens.xml) px(Pixel) 以畫面真實的像素做為單位 mm(Millimeter)
以畫面的毫米為單位 in(inches) 以畫面的英吋作為單位 pt(Points) 一點的單位為1/72英吋 dp&dip 相對於160dpi的螢幕中的一個像素 sp 隨著螢幕大小改變的一個像素

56 Dimens.xml 在JAVA原始檔中使用 用法:R.dimen.尺寸變數名稱
範例:float dimen = getResource().getDiemnsion(R.dimne.px);

57 Dimens.xml 在XML文件中使用

58 Dimens.xml 樣式資源檔 - styles.xml
在此文件中主要是使用<style>定義手機程式佈局,並加入<item>標籤作細部設定。 Style資源檔是類似一般手機上可套用的佈景主題,它可以整合許多屬性,並提供給系統使用,像是前面所介紹的<string>、<color>、<dimen>、<drawable>等等標籤。在此文件中主要是使用<style>定義手機程式佈局,並加入<item>標籤作細部設定。

59 Dimens.xml 在JAVA原始檔中使用 用法:R.style.樣式變數名稱
範例:setTheme(R.style.newStyle);

60 Dimens.xml 在XML文件中使用 用法:@style/樣式變數名稱

61 Layout\main.xml 視窗佈局資源檔 - layout\main.xml
在Android 平台裡,使用者介面都是透過ViewGroup或View類別來顯示,ViewGroup和View是Android平台上最基本的使用者介面元件。 我們可以透過程式直接呼叫的方法,或是使用XML文件,來描述使用者介面。 在Android 平台裡,使用者介面都是透過ViewGroup或View類別來顯示,ViewGroup和View是Android平台上最基本的使用者介面元件。 我們可以透過程式直接呼叫的方法,描繪使用者介面,將螢幕上顯示的介面元素,與構成應用程式的程式邏輯,混合在一起撰寫。 另一種是目前較為大眾所採用的,是將使用者介面與程式邏輯分開撰寫,使用XML文件,來描述使用者介面,與MVC的觀念相似。

62 Layout\main.xml

63 Layout\main.xml 在JAVA中使用: 用法:R.layout.佈局檔案名稱
範例:setContentView(R.layout.main);

64 Anim.xml 動畫資源檔 - anim.xml
首先在res底下建立anim資料夾,並在資料夾中建立anim.xml透過這個資源檔可以達成程式裡面的一些動畫效果 Animation主要有兩種動畫模式:一種是漸變動畫(alpha、scale),另一種是轉場動畫(translate、rotate)。 首先在res底下建立anim資料夾,並在資料夾中建立anim.xml透過這個資源檔可以達成程式裡面的一些動畫效果, 包括文字、按鈕、對話方塊等等具備旋轉、翻轉的功能,這些動作就必須透過anim.xml來完成。 動畫資源檔的標籤為<set>,在其中可以設定的有<alpha>、<scale>、<translate>、<rotate>標籤設定動畫效果。 Animation主要有兩種動畫模式:一種是漸變動畫(alpha、scale),另一種是轉場動畫(translate、rotate)。

65 動畫資源檔文件內容

66 動畫資源檔 動畫資源的使用方法: 首先要引入相關的Package,加入android.view.animation.AnimationUtils;

67 Anim.xml 在JAVA中使用: 用法:R.anim.動畫資源檔名稱
範例:AnimationUtils.loadAnimation(this, R.anim.anim);

68 圖檔資源目錄 圖檔資源目錄 (drawable) 舉凡程式的圖示、背景圖片等等,皆需放在drawable目錄底下
Android會為每個放置在res/drawable目錄下的圖片檔案產生一變數,變數名稱就是這個圖片的檔名(不包含副檔名),可在R.java文件中的drawable中查詢。  舉凡程式的圖示、背景圖片等等,皆需放在drawable目錄底下,Android可以接受的圖檔類型為png、jpg、gif。 Android會為每個放置在res/drawable目錄下的圖片檔案產生ID,ID就是這個圖片的檔名,如果一張圖片的檔名是app_icon.png那麼就會在R.java文件中的drawable下產生

69 圖檔資源目錄 在JAVA原始檔中使用 用法:R.drawable.圖檔名稱
範例:Drawable bitmap = getResources().getDrawable(R.drawable.icon);

70 圖檔資源目錄 在XML文件中使用 用法:@drawable/圖檔名稱

71 Q&A


Download ppt "Android Application Framework"

Similar presentations


Ads by Google