天天看點

upnp 學習筆記二

現在從用戶端入手

剛搭的環境eclipse4.2+adt20

建立工程UpnpBrowser-110712

下載下傳用戶端源碼

http://4thline.org/projects/download/misc/UpnpBrowser-110712.tar.gz

包解壓後将應用源碼直接複制過來

可能缺少兩個jar包

cling-core-1.0.5.jar

teleal-common-1.0.13.jar

不要放在libs目錄下,這樣好象不能source attachment

下載下傳源碼檔案導入工程這樣就可以檢視cling的源碼了

示例代碼如下:

public class MainActivity extends TabActivity {

private static Logger log = Logger.getLogger

(MainActivity.class.getName());

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// Fix the logging integration between java.util.logging and

Android internal logging

LoggingUtil.resetRootHandler(new FixedAndroidHandler());

Logger.getLogger("org.teleal.cling").setLevel(Level.INFO);

setContentView(R.layout.main);

TabHost tabHost = getTabHost();

TabHost.TabSpec spec;

Intent intent;

// 顯示裝置清單頁

intent = new Intent().setClass(this, BrowseActivity.class);

spec = tabHost.newTabSpec("browse").setIndicator("Browse LAN",

getResources().getDrawable(R.drawable.ic_tab_browse)).setContent(intent);

tabHost.addTab(spec);

// 開關示範執行個體

intent = new Intent().setClass(this, DemoActivity.class);

spec = tabHost.newTabSpec("demo").setIndicator("Demo Light",

getResources().getDrawable(R.drawable.ic_tab_demo)).setContent(intent);

tabHost.addTab(spec);

tabHost.setCurrentTab(0);

}

}

@SuppressWarnings("rawtypes")

public class BrowseActivity extends ListActivity {

// private static final Logger log = Logger.getLogger

(BrowseActivity.class.getName());

private ArrayAdapter<DeviceDisplay> listAdapter;

// 遠端裝置監聽(裝置的添加/删除/更新)

private BrowseRegistryListener registryListener = new

BrowseRegistryListener();

private AndroidUpnpService upnpService;

//

private ServiceConnection serviceConnection = new ServiceConnection() {

public void onServiceConnected(ComponentName className, IBinder

service) {

upnpService = (AndroidUpnpService) service;

// Refresh the list with all known devices

// 重新整理裝置清單,顯示可見裝置

// registry 用于存放裝置和裝置資訊

// A running UPnP stack has one <code>Registry</code>

listAdapter.clear();

for (Device device : upnpService.getRegistry

().getDevices()) {

registryListener.deviceAdded(device);

}

// Getting ready for future device advertisements

upnpService.getRegistry().addListener

(registryListener);

// Search asynchronously for all devices

// 查找同步裝置

upnpService.getControlPoint().search();

}

public void onServiceDisconnected(ComponentName className) {

upnpService = null;

}

};

@SuppressWarnings("unchecked")

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

listAdapter = new ArrayAdapter(this,

android.R.layout.simple_list_item_1);

setListAdapter(listAdapter);

// 邦定upnp裝置搜尋服務

getApplicationContext().bindService(new Intent(this,

BrowserUpnpService.class), serviceConnection, Context.BIND_AUTO_CREATE);

}

@Override

protected void onDestroy() {

super.onDestroy();

if (upnpService != null) {

upnpService.getRegistry().removeListener

(registryListener);

}

getApplicationContext().unbindService(serviceConnection);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// 搜尋裝置

menu.add(0, 0, 0, R.string.search_lan).setIcon

(android.R.drawable.ic_menu_search);

// 開關網絡

menu.add(0, 1, 0, R.string.switch_router).setIcon

(android.R.drawable.ic_menu_revert);

// 開關日志

menu.add(0, 2, 0, R.string.toggle_debug_logging).setIcon

(android.R.drawable.ic_menu_info_details);

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case 0:

searchNetwork();

break;

case 1:

if (upnpService != null) {

SwitchableRouter router = (SwitchableRouter)

upnpService.get().getRouter();

if (router.isEnabled()) {

Toast.makeText(this,

R.string.disabling_router, Toast.LENGTH_SHORT).show();

router.disable();

} else {

Toast.makeText(this,

R.string.enabling_router, Toast.LENGTH_SHORT).show();

router.enable();

}

}

break;

case 2:

Logger logger = Logger.getLogger("org.teleal.cling");

if (logger.getLevel().equals(Level.FINEST)) {

Toast.makeText(this,

R.string.disabling_debug_logging, Toast.LENGTH_SHORT).show();

logger.setLevel(Level.INFO);

} else {

Toast.makeText(this,

R.string.enabling_debug_logging, Toast.LENGTH_SHORT).show();

logger.setLevel(Level.FINEST);

}

break;

}

return false;

}

protected void searchNetwork() {

if (upnpService == null)

return;

Toast.makeText(this, R.string.searching_lan,

Toast.LENGTH_SHORT).show();

upnpService.getRegistry().removeAllRemoteDevices();

upnpService.getControlPoint().search();

}

protected class BrowseRegistryListener extends DefaultRegistryListener

{

@Override

public void remoteDeviceDiscoveryStarted(Registry registry,

RemoteDevice device) {

deviceAdded(device);

}

@Override

public void remoteDeviceDiscoveryFailed(Registry registry,

final RemoteDevice device, final Exception ex) {

showToast("Discovery failed of '" +

device.getDisplayString() + "': " + (ex != null ? ex.toString() : "Couldn't

retrieve device/service descriptors"), true);

deviceRemoved(device);

}

@Override

public void remoteDeviceAdded(Registry registry, RemoteDevice

device) {

deviceAdded(device);

}

@Override

public void remoteDeviceRemoved(Registry registry, RemoteDevice

device) {

deviceRemoved(device);

}

@Override

public void localDeviceAdded(Registry registry, LocalDevice

device) {

deviceAdded(device);

}

@Override

public void localDeviceRemoved(Registry registry, LocalDevice

device) {

deviceRemoved(device);

}

public void deviceAdded(final Device device) {

runOnUiThread(new Runnable() {

public void run() {

DeviceDisplay d = new DeviceDisplay

(device);

int position = listAdapter.getPosition

(d);

if (position >= 0) {

// Device already in the list,

re-set new value at same position

listAdapter.remove(d);

listAdapter.insert(d,

position);

} else {

listAdapter.add(d);

}

// Sort it?

// listAdapter.sort

(DISPLAY_COMPARATOR);

// listAdapter.notifyDataSetChanged();

}

});

}

public void deviceRemoved(final Device device) {

runOnUiThread(new Runnable() {

public void run() {

listAdapter.remove(new DeviceDisplay

(device));

}

});

}

}

protected void showToast(final String msg, final boolean longLength) {

runOnUiThread(new Runnable() {

public void run() {

Toast.makeText(BrowseActivity.this, msg,

longLength ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show();

}

});

}

protected class DeviceDisplay {

Device device;

public DeviceDisplay(Device device) {

this.device = device;

}

public Device getDevice() {

return device;

}

@Override

public boolean equals(Object o) {

if (this == o)

return true;

if (o == null || getClass() != o.getClass())

return false;

DeviceDisplay that = (DeviceDisplay) o;

return device.equals(that.device);

}

@Override

public int hashCode() {

return device.hashCode();

}

@Override

public String toString() {

String name = device.getDetails() != null &&

device.getDetails().getFriendlyName() != null ? device.getDetails

().getFriendlyName() : device.getDisplayString();

// Display a little star while the device is being

loaded (see performance optimization earlier)

return device.isFullyHydrated() ? name : name + " *";

}

}

static final Comparator<DeviceDisplay> DISPLAY_COMPARATOR = new

Comparator<DeviceDisplay>() {

public int compare(DeviceDisplay a, DeviceDisplay b) {

return a.toString().compareTo(b.toString());

}

};

}

public class DemoActivity extends Activity implements PropertyChangeListener {

private static final Logger log = Logger.getLogger

(DemoActivity.class.getName());

private AndroidUpnpService upnpService;

private UDN udn = UDN.uniqueSystemIdentifier("Demo Binary Light");

private ServiceConnection serviceConnection = new ServiceConnection() {

public void onServiceConnected(ComponentName className, IBinder

service) {

upnpService = (AndroidUpnpService) service;

// 取得type為SwitchPower的LocalService

LocalService<SwitchPower> switchPowerService =

getSwitchPowerService();

// Register the device when this activity binds to the

service for the first time

// 在服務邦定後注冊裝置

if (switchPowerService == null) {

try {

// 建立裝置

LocalDevice binaryLightDevice =

createDevice();

Toast.makeText(DemoActivity.this,

R.string.registering_demo_device, Toast.LENGTH_SHORT).show();

// 添加裝置

upnpService.getRegistry().addDevice

(binaryLightDevice);

switchPowerService =

getSwitchPowerService();

} catch (Exception ex) {

log.log(Level.SEVERE, "Creating demo

device failed", ex);

Toast.makeText(DemoActivity.this,

R.string.create_demo_failed, Toast.LENGTH_SHORT).show();

return;

}

}

// Obtain the state of the power switch and update the

UI

// 取得狀态并更新ui

setLightbulb(switchPowerService.getManager

().getImplementation().getStatus());

// Start monitoring the power switch

switchPowerService.getManager().getImplementation

().getPropertyChangeSupport().addPropertyChangeListener(DemoActivity.this);

}

public void onServiceDisconnected(ComponentName className) {

upnpService = null;

}

};

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.demo);

// 邦定BrowserUpnpService服務

getApplicationContext().bindService(new Intent(this,

BrowserUpnpService.class), serviceConnection, Context.BIND_AUTO_CREATE);

}

@Override

protected void onDestroy() {

super.onDestroy();

// Stop monitoring the power switch

// 停止開關監聽

LocalService<SwitchPower> switchPowerService =

getSwitchPowerService();

if (switchPowerService != null)

switchPowerService.getManager().getImplementation

().getPropertyChangeSupport().removePropertyChangeListener(this);

// 解除邦定

getApplicationContext().unbindService(serviceConnection);

}

public void propertyChange(PropertyChangeEvent event) {

if (event.getPropertyName().equals("status")) {

log.info("Turning light: " + event.getNewValue());

setLightbulb((Boolean) event.getNewValue());

}

}

protected void setLightbulb(final boolean on) {

runOnUiThread(new Runnable() {

public void run() {

ImageView imageView = (ImageView) findViewById

(R.id.demo_imageview);

imageView.setImageResource(on ?

R.drawable.lightbulb : R.drawable.lightbulb_off);

// You can NOT externalize this color into

/res/values/colors.xml. Go on, try it!

imageView.setBackgroundColor(on ?

Color.parseColor("#9EC942") : Color.WHITE);

}

});

}

protected LocalService<SwitchPower> getSwitchPowerService() {

if (upnpService == null)

return null;

// 本地裝置(中繼資料)

LocalDevice binaryLightDevice;

if ((binaryLightDevice = upnpService.getRegistry

().getLocalDevice(udn, true)) == null)

return null;

// 取得服務類型為SwitchPower的裝置中繼資料資訊

return (LocalService<SwitchPower>)

binaryLightDevice.findService(new UDAServiceType("SwitchPower", 1));

}

protected LocalDevice createDevice() throws ValidationException,

LocalServiceBindingException {

DeviceType type = new UDADeviceType("BinaryLight", 1);

DeviceDetails details = new DeviceDetails("Friendly Binary

Light", new ManufacturerDetails("ACME"), new ModelDetails("AndroidLight", "A

demo light with on/off switch.", "v1"));

LocalService service = new AnnotationLocalServiceBinder().read

(SwitchPower.class);

service.setManager(new DefaultServiceManager<SwitchPower>

(service, SwitchPower.class));

return new LocalDevice(new DeviceIdentity(udn), type, details,

createDefaultDeviceIcon(), service);

}

protected Icon createDefaultDeviceIcon() {

return new Icon("image/png", 48, 48, 8, URI.create("icon.png"),

"89504E470D0A1A0A0000000D494844520000002D000000300803000000B28C03ED000000197445

5874536F6674"

+

"776172650041646F626520496D616765526561647971C9653C00000300504C5445EEF2DBAAAAAB

F5F5" +

"F5EEEEF2D1DDBABCC99DCBD2CBC5D0AB88888AFCFCFCD6E6B1CEDAB0BEC9A1F1F1F1F1F5DCDCEA

B6D6"

+

"E2B6D9E4BAB5C78DEAEECCDAE5BCB3BA95D6E1B8DDEEB9C4CCBDB2B3B3CDD9BAE6EEC2F6F6F8D9

EAAD" +

"DBDDE2EEF3E1C4CEABA4A3A5CDD9AED1D1D1CDDDA9DDECB6D4E3B1DDEDB1656466FAFAFABCBCBC

C9D9"

+

"A6D2DDB5D8E6B4CDDAC2D8E2B9D5DADB899A6BD9DADD9BA684DAEAB0D5E7AACBD6C4F8F8F8C6D2

A7EA" +

"EDD1CED3D0E8E8E9D4D7D9E6E6E6BFCD9ECAD6ADD5E7ADE2EEBDC6D5A2ECEFD59EA47DDBE9B6CF

DCAD"

+

"ABB594DAECAF7B8D60D1DEC3A6AB81D6E2BEBBCE91B3C696C3C2C3C9C9CAC1CEA1E4E4E9D9E5B6

D6E3" +

"B4D1D6D4C9D4A9C6CDC1E3F0BCB9C197D2D9D5D1E1AAC7CDC5C9DC9FC6D89DD7E9ADB1B78DE2EE

BAE3"

+

"E3E3D9D8D8EEF1D7D5D5D5A2B28DB9C19AD2E1AE595959C1BFC2E5E6ECCDDEA6C8D3AACAD7A4A2

A593" +

"D4E0B4FAFAFCB1AFB2D1CED3DEE0E6C5CBC2C9D5BAD4DFB5DEF0B6DFECB7D3E0BED2E0B9CCCCCD

4645"

+

"47EDEDEDD3DEB4DAE8B5D5E0B6D3E4AAD1E2A6D4D2D5D1DDB1E2F2B9C9D3ADD6E1B6CBDAAFC7D0

C2C0" +

"CBA4D1DCB2B9C29EC8D8A3D4E2AFD3DFB1C5D2A2A7A89DE9E9EFE5F0C0E1E2E9E0EFB5DAEBB5D8

E6B2"

+

"CBDBA7CCD7ADC7D7A5C4CFA6C2CAA0BDC69FBBC69DE5F3BEE4F2BBDDDDDDD7E5B4D8E4B5CFDBB1

DAE6" +

"B7FFFFFED2DDB3D8D8D7F9F9F9D9E7B5FEFEFDC1D0A7CECACFE0EFBAA0A67FF3F3F6DEEFB0BFCA

BAD8"

+

"D4DBD5E1B4AFC08D727173AFC396D9E3BCCBD8AACED9AAD3E0B2D0DFACC2D1A1CDCBD0A1A0A2CF

E0A9" +

"D7E3B6FBFCFDFBFBFBFDFDFDA5AD90D1D0D49B9F8FD6E1C1B6CA94E0F0B5B7C397677A51EBEDD4

EBEE"

+

"D2C0D392C8CDC7C2D29EB5C2A5BCC6A4D8EAAADBECB3DCEAB3DCDBDEE0E1E6D3DFB3CFDDB6AFAB

B2C1" +

"CEA6E3F4BBA8BB84E1E3EDCCD8B4A4B782D3E6B1A9B086ACB28A3E3D3FBAC79B5F6E4ED3DDB1F0

EFF4"

+

"E6EEC8ECEEF8CBCACEE7EFC4CCD0CD90A473EAEFCECCD6AAE1EDBAE0EEBAE2EFB8A2A39AA6A5A7

A1A6" +

"8AADAFA6A7AE89A7AC83E9F5C0D9E8B3FEFEFEFFFFFFF96070A50000043A4944415478DA62F84F

0A60"

+

"C022F6AFB0B0F02871AA0FBFB97839CD38CD7D73E846B8EE7F38546B3E30F07B74FF85A7E7D90F

DB76" +

"18BC81A9FE8755F5E428AF36DFD85843434F4F5F8F53265E72475095A3A89EAA375D7CE1E9B838

A10B"

+

"BEBE57E34CEF557845C9E0545D5276AD627DC4823FBB5959CF6CCB5BB8202242DC2B14453992EA

EC32" +

"AE6BD3BEB64DF9C8C00702291FA744447CF10AE5C4AA5AA66B2F97FAB4699BDE3933C88301C3F9

7711"

+

"EB55F54A900C47A8B661CF70708897DDF4EEBC3303583D83F3C7880AF1E9661BB1A89691D8A592

D36C" +

"2AEB3145D8D2398501049C85A779C44F9792438439038C715321CCA9AFD9D4D4E3EB9477C2E79D

5352"

+

"9CCF59BEDBE461DAF4D8EA30DC70B8EAD03976817D394DA626AA898ED2D2AF853F9EB7144E5497

75C8" +

"3968F60A6E384CF5D18B779FDB39CD3CD864725DB5F2F3E7C4C408474747759378879CBECE6CB0

6A64"

+

"979897769F619DD837339AEBEF75FE4A0850353171689E79296C2A72AA02AB9691E039C31AE8A4

BD57" +

"6DC66A5757FE4AD5CA4A7E5793C7D12A7D766B4B305C2253CA7366BEDDC4896EFD5CBAAB1B5C41

A0E1"

+

"2F57B4CACC3ED6BB25182E3912D33D9F676EA0859B1A97AEEEEAD50D0D0DAB57EBF6ABA8CC7462

65C7" +

"74F77FAB39DD732C2C3EB94D080959AC0B04AB1B7467F4CFD49EBD8F558219D9251020C7CE6E61

6F3F"

+

"8BBB756BC892E0E065CB96E9EACE5053D19E1DD8CDB60A39BC218059A23DD75E4989BB75C2D625

4B80" +

"EA83972CE652CBE8DC65C16E84129710B0C6AADD7E9612F7D29E5B5B05040E01C19210B53DAD4B

95EC"

+

"BB400EF977142D554D9678C80D54BCA2BE00A81AA43E64EBAD97DC9D5D06CBB1A9FE6F23B114A4

B8BC" +

"BC430064BA804041797DCF6DAB8D48191949B5F9FBA5F540B58D8D1D62026240E31B1B1BABABD9

26E3"

+

"C83BFF9963741AC5C404F4050EE9EBEB83B058355B094A1981928BB3BBAAC5808A0461C0C7CAE8

286E" +

"D5FFE56258C40405452060A74F958DE67F3CAA35ADA458C4F47742D4FA9CB462C65FB205850395

030D"

+

"DF0934B8AACA660D7ED532A50FCB410EDFA9AF5FC5221544A8D47CCFCEDDA323A62FD658DFF330

FC15" +

"21D53657D8EDB997AEE8E1569A951B6E4E48B5512FCF9CDCB0B0B05C0BF6EEF0A328C53116D572

A2E9"

+

"F3E602010FCFBCDED2E5F06C80CB6C7751D1C8C833914020FA9E60DD607DECD7D30408703722A8

FAE8" +

"4F970DDEBF41E049FE2282AA97677DFBE1E2E2B2C1C5F8048732E15A4AAB48EBE7A4FC49931439

3289"

+

"507D2093F1EDF1962DFB19356A93D103105375D1330DC6FDC5EBB214336B935769721EC5A3FADF

D155" +

"C91ADBEF146F29F657D4E048B6DEB88A13A7EA7F4739CDEB8C18398A5A8C6E047CE7D0AA49E235

C7A7"

+

"5A93C95AD99FF100A36411E37749FF54EB8D9AF8541F61AA4B52F697BCC3C858A415906ACB2B73

E41F" +

"EE30F9C7B98AA9CE7691724D408D726A9235AF0C9A27317CA969CEC46B9B9494646BBD9169D511

F496"

+

"04408001003EE42959E2CD74A60000000049454E44AE426082");

}

}

@UpnpService(serviceId = @UpnpServiceId("SwitchPower"), serviceType =

@UpnpServiceType(value = "SwitchPower", version = 1))

public class SwitchPower {

// 維護狀态改變

private final PropertyChangeSupport propertyChangeSupport;

public SwitchPower() {

this.propertyChangeSupport = new PropertyChangeSupport(this);

}

public PropertyChangeSupport getPropertyChangeSupport() {

return propertyChangeSupport;

}

@UpnpStateVariable(defaultValue = "0", sendEvents = false)

private boolean target = false;

@UpnpStateVariable(defaultValue = "0")

private boolean status = false;

@UpnpAction

public void setTarget(@UpnpInputArgument(name = "NewTargetValue")

boolean newTargetValue) {

boolean targetOldValue = target;

target = newTargetValue;

boolean statusOldValue = status;

status = newTargetValue;

// These have no effect on the UPnP monitoring but it's

JavaBean compliant

getPropertyChangeSupport().firePropertyChange("target",

targetOldValue, target);

getPropertyChangeSupport().firePropertyChange("status",

statusOldValue, status);

// This will send a UPnP event, it's the name of a state

variable that sends events

getPropertyChangeSupport().firePropertyChange("Status",

statusOldValue, status);

}

@UpnpAction(out = @UpnpOutputArgument(name = "RetTargetValue"))

public boolean getTarget() {

return target;

}

@UpnpAction(out = @UpnpOutputArgument(name = "ResultStatus"))

public boolean getStatus() {

return status;

}

}

public class BrowserUpnpService extends AndroidUpnpServiceImpl {

@Override

protected AndroidUpnpServiceConfiguration createConfiguration(WifiManager

wifiManager) {

return new AndroidUpnpServiceConfiguration(wifiManager) {

};

}

}

清單檔案中注冊:

<!-- Custom AndroidUpnpServiceImpl - see the source -->

<!-- 聲明自定義service -->

<service android:name=".BrowserUpnpService" />

繼續閱讀